利用Python抓取指定微博用户新发的动态,并通过邮件进行通知 ~

环境需求

  • Python 3.x
  • 第三方库:BeautifulSoup

    食用方法

    获取用户oid

    首先需要获取目标用户的oid。进入目标用户主页,按F12打开控制台,在Element页按Ctrl+F打开搜索栏,输入oid即可,然后将oid填入get_weibo.py

    1. if __name__ == '__main__':
    2. oid = "" # 指定用户oid
    3. headers = {
    4. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
    5. 'Chrome/71.0.3578.98 Safari/537.36',
    6. }

    Python - 获取指定微博用户最新动态 - 图1

    配置SMTP

    主要用于接收对方更新微博时的通知。 邮箱端配置好SMTP后,打开get_weibo.py,找到send_email()函数,设置邮箱发送邮箱、接收邮箱、SMTP授权码以及SMTP服务器

    1. # 发送邮件
    2. def send_email(weibo_text, date, imgs):
    3. with open('get_weibo.txt', 'a+') as f:
    4. for img in imgs: # 如果有图片则以img标签形式追加到文本
    5. weibo_text += f'<img src="{img}">'
    6. f.write(weibo_text) # 把微博内容写入文本记录
    7. # 设置收发邮箱
    8. to_addr = '' # 接收邮箱
    9. from_addr = '' # 发送邮箱
    10. password = '' # 发送邮箱打开SMTP服务生成的第三方授权码,不是登陆密码!!!
    11. smtp_server = '' # 设置SMTP服务器

    运行

  • 配置好上面对应参数后,即可运行。Linux中后台运行命令如下:

    1. $ nohup python get_weibo.py
    2. # 若出现错误:`nohup: ignoring input and appending output to ‘nohup.out`,则使用下面这条命令
    3. $ nohup python -u get_weibo.py > nohup.out 2>&1 &
  • 如果未安装BeautifulSoup库,需要先安装一下

    1. $ pip install bs4
  • 若要停止运行,先用ps命令查看进程号,然后使用kill命令终止

    1. # 查看进程号
    2. $ ps -aux|grep get_weibo.py | grep -v grep
    3. # 终止运行
    4. $ kill -9 进程号

    完整代码

  • 微博接口改了,返回的数据中,微博发送时间的格式变成了中国标准时间格式,如Tue Apr 26 18:00:00 +0800 2022。因此需要再次对其进行解析,并且判断是否新发微博的if语句也需修改 ```python

    -- coding: utf-8 --

    get_weibo.py

    import re import time import json import requests import smtplib from bs4 import BeautifulSoup from email import encoders from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr

获取页面json

def get_data(url, headers): r = requests.get(url, headers=headers) content = r.content data = json.loads(content)[‘data’] # json转为dic return data

获取用户主页id,用于后续爬取

def get_containerid(data): tabs = data[‘tabsInfo’][‘tabs’] for tab in tabs: if tab[‘tab_type’] == ‘weibo’: containerid = tab[‘containerid’] return containerid

获取用户信息

def get_userInfo(data): screen_name = data[‘userInfo’][‘screen_name’] # 微博昵称 profile_url = data[‘userInfo’][‘profile_url’] # 微博地址 follow_count = data[‘userInfo’][‘follow_count’] # 关注人数 followers_count = data[‘userInfo’][‘followers_count’] # 粉丝数 userInfo = { ‘微博昵称’: screen_name, ‘微博地址’: profile_url, ‘关注人数’: follow_count, ‘粉丝数’: followers_count } return userInfo

解析微博内容

def parse_weibo(weibo_data, headers): cards = weibo_data[‘cards’] mblog = cards[0][‘mblog’] # 每个cards[i]为一组微博,第0个为最新或置顶 imgs = [] # 图片列表,用于保存图片url,初始为空 try: if ‘置顶’ == mblog[‘title’][‘text’]: # 判断是否含有置顶 mblog = cards[2][‘mblog’] except KeyError as e: pass if ‘pics’ in mblog: # 判断微博内容有没有包含图片 pics = mblog[‘pics’] for pic in pics: imgs.append(pic[‘url’]) created_at = mblog[‘created_at’] # 微博发布日期 text = mblog[‘text’] # 微博内容,包含html标签

  1. # 如果未显示全文,需跳转到全文页面获取内容
  2. if '全文' in text: # 需跳转到全文的微博,匹配其跳转连接
  3. href_url = re.findall('<a href="(.*?)\">全文', text)[0]
  4. full_url = f"https://m.weibo.cn{href_url}"
  5. response = requests.get(full_url, headers=headers) # 获取全文网页
  6. full_page = response.text
  7. soup = BeautifulSoup(full_page, 'lxml')
  8. script = soup.select("script")[1].string # 未登录时,微博内容存放在<script>内
  9. text = re.findall('"text": (.*)', script)[0]
  10. text = re.sub(r'href=\\"', 'href="', text) # 匹配去除href后面斜杠,href=\"www...com"
  11. text = re.sub('src="//h5(.*?)', 'src=\"http://h5', text) # 匹配微博表情,添加http才可以显示
  12. return text,created_at,imgs

格式化邮件地址函数

def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, ‘utf-8’).encode(), addr))

发送邮件

def send_email(weibo_text, date, imgs): with open(‘get_weibo.txt’, ‘a+’) as f: for img in imgs: # 如果有图片则以img标签形式追加到文本 weibo_text += f’Python - 获取指定微博用户最新动态 - 图2‘ f.write(weibo_text) # 把微博内容写入文本记录

  1. # 设置收发邮箱
  2. to_addr = '' # 接收邮箱
  3. from_addr = '' # 发送邮箱
  4. password = '' # 发送邮箱打开SMTP服务生成的第三方授权码,不是登陆密码!
  5. smtp_server = '' # 设置SMTP服务器
  6. # 格式化邮件信息
  7. msg = MIMEText(weibo_text, 'html', 'utf-8') # 邮件内容
  8. msg['To'] = _format_addr(f'收件人 <{to_addr}>' ) # 收件人
  9. msg['From'] = _format_addr(f'发件人 <{from_addr}>') # 发件人
  10. msg['Subject'] = Header(f'{date} - 微博爬虫', 'utf-8').encode() # 邮件标题
  11. # 发送
  12. try:
  13. # server = smtplib.SMTP(smtp_server, 25)
  14. server = smtplib.SMTP_SSL(smtp_server, 465)
  15. server.set_debuglevel(1)
  16. server.login(from_addr, password)
  17. server.sendmail(from_addr, [to_addr], msg.as_string())
  18. print("发送成功")
  19. server.quit()
  20. except smtplib.SMTPException as e:
  21. print('发送失败,Case:%s' % e)

if name == ‘main‘: oid = “” # 指定用户oid headers = { ‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ‘ ‘Chrome/71.0.3578.98 Safari/537.36’, }

  1. # 通过主页面json获取用户信息和用户主页containerid
  2. url = f'https://m.weibo.cn/api/container/getIndex?type=uid&value={oid}' # 主页url
  3. data = get_data(url, headers) # 主页面json
  4. userInfo = get_userInfo(data) # 用户信息
  5. containerid = get_containerid(data) # 用户主页containerid
  6. # print(containerid)
  7. while True:
  8. print("开始获取...")
  9. # 通过containerid获取微博页面json,并解析微博页面json得到微博内容
  10. weibo_url = f'https://m.weibo.cn/api/container/getIndex?type=uid&value={oid}&containerid={containerid}&page=1'
  11. weibo_data = get_data(weibo_url, headers) # 微博页面json
  12. weibo_text,date,imgs = parse_weibo(weibo_data, headers) # 微博内容和日期,这里设为第0条,即最新一条
  13. # 微博接口修改了时间格式
  14. weibo_time = time.strptime(date, "%a %b %d %H:%M:%S +0800 %Y") # 解析某条微博发出时间
  15. weibo_time = int(time.mktime(weibo_time)) # 转换为时间戳
  16. seconds = int(time.time()) - weibo_time # 当前时间减发出时间
  17. # if ('刚刚' in date) or ("分钟" in date and int(date[:-3]) <= 10): # 微博刚刚发出或发出时间小于10分钟
  18. if (seconds < 6000): # 微博发出时间小于10分钟
  19. print("有新的微博,准备发邮件...")
  20. flag = True
  21. with open('get_weibo.txt', 'a+') as f:
  22. line = f.readline() # 逐行读取,判断微博内容是否已发送过(即已存在txt中)
  23. while line:
  24. if weibo_text in txt:
  25. flag = False
  26. line = f.readline()
  27. if flag: # 不存在txt中则发送
  28. send_email(weibo_text, date, imgs)
  29. print("本次抓取完成,休息5分钟...")
  30. time.sleep(300)

```