Trong blog của tôi có một loạt bài viết mang tên “Những suy nghĩ nhỏ”, thực chất là bản sao lưu cá nhân từ Weibo của tôi. Tuy 2bet nhiên, việc duy trì này luôn được thực hiện bằng tay và khá mất thời gian. Gần đây, tôi đã tạo ra một kịch bản Python có khả năng tự động trích xuất nội dung Weibo và chuyển đổi nó thành định dạng phù hợp với loạt bài “Những suy nghĩ nhỏ”. Bài viết mới nhất của loạt này (tháng 12 năm 2020) đã được sinh ra hoàn toàn nhờ vào kịch bản này.
Để sử dụng kịch bản này, bạn cần:
- Đăng nhập vào Weibo để lấy thông tin cookie và user-agent.
- Sử dụng API lật trang Weibo.
- Sử dụng API mở rộng cho các bài Weibo dài.
- Thư viện Python bên thứ ba - requests.
Để đảm bảo lưu trữ đầy đủ, kịch bản này thực hiện:
- Lấy toàn bộ nội dung của bài viết bất cứ khi nào có thể.
- Bao gồm cả những bài Weibo được chia sẻ lại.
- Tải xuống hình ảnh và lưu trữ chúng cục bộ.
- Thay thế các liên kết rút gọn bị chặn bởi Weibo bằng các liên kết gốc.
Tôi không phải là lập trình viên chuyên nghiệp, vì vậy mã nguồn của tôi còn khá thô sơ. Kịch bản này chỉ hoạt động trên máy tính của tôi kèo bóng đá (macOS + Python 3.8). Dưới đây là mã nguồn đầy đủ:
import requests
from datetime import datetime
import random
import time
# Chỉ lấy nội dung sau thời điểm YYYYMM
NAM_THANG = datetime.strptime('202012', '%Y%m')
# Đổi thông tin đăng nhập của bạn ở đây
THONG_TIN_DANG_NHAP = {
'cookie': '',
'user-agent': ''
}
# Lấy nội dung của một bài Weibo đơn lẻ, không bao gồm phần chia sẻ lại
def lay_bai_weibo(doi_tuong_json):
ma_bai = doi_tuong_json['mblogid']
link_bai = ' + ma_bai
ngay_dang = datetime.strptime(doi_tuong_json['created_at'].replace('+0800',''),'%a %b %d %H:%M:%S %Y')
chuoi_ngay = time.strftime('%Y-%m-%d %H:%M')
ten_nguoi_dung = doi_tuong_json['user']['screen_name']
if doi_tuong_json['isLongText'] == True:
du_lieu_dai = requests.get(' + ma_bai)
noi_dung_nguyen_ban = du_lieu_dai.json()['longTextContent'].replace('\u200b','').strip()
if 'url_struct' in du_lieu_dai.json().keys():
noi_dung_nguyen_ban = thay_the_url(noi_dung_nguyen_ban, du_lieu_dai.json()['url_struct'])
else:
noi_dung_nguyen_ban = doi_tuong_json['text_raw'].replace('\u200b','').strip()
if 'url_struct' in doi_tuong_json.keys():
noi_dung_nguyen_ban = thay_the_url(noi_dung_nguyen_ban, doi_tuong_json['url_struct'])
danh_sach_hinh_anh = doi_tuong_json['pic_ids']
van_ban_hinh_anh = ''
for id_hinh in danh_sach_hinh_anh:
link_hinh = doi_tuong_json['pic_infos'][id_hinh]['original']['url']
ten_hinh = tai_xuong_hinh(link_hinh)
van_ban_hinh_anh += '![[' + ten_hinh + ']]' + '\n'
van_ban_bai = '@{ten_nguoi_dung}:{noi_dung}\n\n{hinh_anh}'.format(
ten_nguoi_dung=ten_nguoi_dung,
noi_dung=noi_dung_nguyen_ban,
hinh_anh=van_ban_hinh_anh
)
return {
'thoi_gian': ngay_dang,
'link': link_bai,
'nguoi_dung': ten_nguoi_dung,
'van_ban': van_ban_bai
}
# Lấy nội dung bài Weibo cùng với phần chia sẻ lại nếu có
def lay_mot_bai_weibo(doi_tuong_json):
bai_chinh = lay_bai_weibo(doi_tuong_json)
noi_dung_toan_bo = ''
if 'retweeted_status' in doi_tuong_json.keys():
bai_chia_se = lay_bai_weibo(doi_tuong_json['retweeted_status'])
noi_dung_toan_bo = '''
Thời gian: {thoi_gian}
Link: {link}
Nội dung gốc: {noi_dung_chinh}
Nội dung chia sẻ: {noi_dung_chia_se}
'''.format(
thoi_gian=bai_chinh['thoi_gian'],
link=bai_chinh['link'],
noi_dung_chinh=bai_chinh['van_ban'],
noi_dung_chia_se=bai_chia_se['van_ban'].strip().replace('\n','<br/>')
)
else:
noi_dung_toan_bo = '''
Thời gian: {thoi_gian}
Link: {link}
Nội dung: {noi_dung}
'''.format(
thoi_gian=bai_chinh['thoi_gian'],
link=bai_chinh['link'],
noi_dung=bai_chinh['van_ban']
)
if 'url_struct' in doi_tuong_json.keys():
noi_dung_toan_bo = thay_the_url(noi_dung_toan_bo, doi_tuong_json['url_struct'])
return {
'thoi_gian': bai_chinh['thoi_gian'],
'noi_dung_toan_bo': noi_dung_toan_bo
}
# Lấy danh sách các bài Weibo trong một trang
def lay_trang_weibo(so_trang, NAM_THANG):
link_trang = ' + str(so_trang)
yeu_cau_trang = requests.get(link_trang, headers=THONG_TIN_DANG_NHAP)
if yeu_cau_trang.json()['ok'] != 1:
return {
'so_trang': so_trang,
'trang_thanh_cong': yeu_cau_trang.json()['ok'],
'duoc_thoi_gian': False,
'danh_sach_bai': []
}
else:
danh_sach_bai = yeu_cau_trang.json()['data']['list']
danh_sach_bai_rieng = []
duoc_thoi_gian = False
for bai in danh_sach_bai:
mot_bai = lay_mot_bai_weibo(bai)
thoi_gian = mot_bai['thoi_gian']
if thoi_gian >= NAM_THANG:
danh_sach_bai_rieng.append(mot_bai)
else:
duoc_thoi_gian = True
return {
'so_trang': so_trang,
'trang_thanh_cong': 1,
'duoc_thoi_gian': duoc_thoi_gian,
'danh_sach_bai': danh_sach_bai_rieng
}
# Lấy tất cả các bài Weibo trong một tháng
def lay_thang_weibo(NAM_THANG):
danh_sach_thang = []
for so_trang in range(1,100):
time.sleep(random.random()*5)
trang_weibo = lay_trang_weibo(so_trang, NAM_THANG)
danh_sach_thang.append(trang_weibo)
if trang_weibo['duoc_thoi_gian'] == True:
break
return danh_sach_thang
# Tải hình ảnh về thư mục pic, thêm tiền tố weibo-yyyymm vào tên file và trả về tên file
def tai_xuong_hinh(url):
ten_hinh = 'weibo-' + NAM_THANG.strftime('%Y%m') + '-' + url.split('?')[0].split('/')[-1]
yeu_cau_hinh = requests.get(url)
with open('pic/'+ten_hinh, 'wb') as f:
f.write(yeu_cau_hinh.content)
return ten_hinh
# Thay thế các liên kết ngắn bằng liên kết dài gốc
def thay_the_url(van_ban, cau_truc_url):
for url in cau_truc_url:
lien_ket_md = '{tieu_de}'.format(tieu_de=url['url_title'], lien_ket=url['long_url'])
van_ban = van_ban.replace(url['short_url'], lien_ket_md)
return van_ban
# Ghi nội dung Weibo vào file md và trả về danh sách các trang thất bại
def cong_viec():
danh_sach_thang = lay_thang_weibo(NAM_THANG)
noi_dung_md = ''
danh_sach_trang_that_bai = []
for trang in danh_sach_thang:
print(trang['so_trang'], ': ', trang['trang_thanh_cong'], '\n')
for bai in trang['danh_sach_bai']:
noi_dung_md = bai['noi_dung_toan_bo'] + noi_dung_md
ten_file = 'Những suy nghĩ nhỏ ({thoi_gian}).md'.format(thoi_gian=NAM_THANG.strftime('%Y%m'))
with open(ten_file,'w') as f:
f.write(noi_dung_md)
cong_viec()
print('hoàn thành')
Hy vọng rằng đoạn mã này sẽ hữu ích cho những ai muốn tự động hóa quá trình sao lưu Weibo của mình!
Sửa đổi lần cuối vào 2025-04-30