出生率创40年来最低,人口几近负增长,微博爬虫爬评论

本文仅用于学习和交流,不具有任何商业价值,如有问题,请与我联系,我将即时处理。

近日,《中国统计年鉴2021年》发布,公布了我国2020年的相关人口数据。据了解,去年我国的人口出生率为8.52‰,直接跌破了10‰的整数关口,创下了我国近43年来的新低。同期全国人口自然增长率(出生率-死亡率)仅为1.45‰,同样创下1978年以来的历史新低。为了减缓人口负增长的到来,我国已经在今年正式开放了三胎政策。一对正处在适龄生育阶段的夫妻,如果想生的话,可以再生一个。

要爬的网址:https://weibo.com/1887344341/L2jya3WQs

要爬取所有评论,打开开发者工具,定位到评论请求的url。

1 https://weibo.com/ajax/statuses/buildComments?is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&count=10&uid=1887344341&type=feed&maxShowTotal=10
2 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=3402343747493173&count=20&uid=1887344341&type=feed&maxShowTotal=10
3 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=430913571822089&count=20&uid=1887344341&type=feed&maxShowTotal=10
4 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=248394641543629&count=20&uid=1887344341&type=feed&maxShowTotal=10

对比url发现,他们之间只差了个max_id。第一页没有max_id。第一页产生的max_id是供第二页的参数使用的,第二页产生的max_id供第三页的参数,以此类推。。。

 从图中看到,总评论数为48363,每页10条,也就有48364 /10,这里爬多线程爬1000页。

 1 """
 2 https://weibo.com/ajax/statuses/buildComments?is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&count=10&uid=1887344341&type=feed&maxShowTotal=10
 3 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=3402343747493173&count=20&uid=1887344341&type=feed&maxShowTotal=10
 4 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=430913571822089&count=20&uid=1887344341&type=feed&maxShowTotal=10
 5 https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id=248394641543629&count=20&uid=1887344341&type=feed&maxShowTotal=10
 6 """
 7 import pprint
 8 import random
 9 import time
10 import openpyxl as op
11 import requests
12 
13 startTime = time.time() # 程序开始时间
14 # 新建一个excel文档
15 wb = op.Workbook()
16 ws = wb.create_sheet(index=0) # 创建一个工作表
17 # 表头
18 ws.cell(row=1, column=1, value='评论者ID') # 第一行第一列,评论者id
19 ws.cell(row=1, column=2, value='评论者名字') # 第一行第二列,评论者名字
20 ws.cell(row=1, column=3, value='评论时间') # 第一行第三列,评论创建时间
21 ws.cell(row=1, column=4, value='评论获赞数') # 第一行第四列,评论获赞数
22 ws.cell(row=1, column=5, value='评论内容') # 第一行第五列,评论内容
23 ws.cell(row=1, column=6, value='评论者位置') # 第一行第六列,评论者所在省市
24 ws.cell(row=1, column=7, value='评论内容带标签') # 第一行第七列,评论内容带html标签,一般是表情的img
25 
26 # def checkInfo():
27 #     """
28 #     判定是否有数据返回,没有就继续请求
29 #     :return:
30 #     """
31 #     if not response.json()['data']['user']:
32 
33 headers = {
34     "cookie": "SCF=AnKJy3NOK5c-P3XxWYBPzTFGd92WnUEH6LUI_MdzSig0jI3pA3K2kjkM9hZTJ0IITPvhB9z0S6v5zBhymsOiVEM.; SINAGLOBAL=2860911667356.4736.1634270617413; UOR=,,login.sina.com.cn; SUB=_2A25MbV1zDeRhGedJ61oQ8SjNyTyIHXVvrmM7rDV8PUJbkNB-LWvFkW1NVnxxfysRCdawBfR6AaMHW6qlF-dAZKcw; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WFCIqm7ZokIkH-v5aWq95ji5NHD95QpS05ReK2ceKz7Ws4Dqcjdi--fiK.7iK.pi--fiKy2iK.Ni--fiKL2i-2p; XSRF-TOKEN=yBO4YQJpwcTtENwqPBhhYOkQ; _s_tentry=weibo.com; Apache=8068250098263.423.1637737323909; ULV=1637737323946:4:3:1:8068250098263.423.1637737323909:1636889723690; WBPSESS=iwgOWzX5ngPbvVwyybpLtabJYNqDLtysUdv2RWzj0AVKPySJ_aVpCAXmkWiTCsG4oWn0sdmqNKI-wNweb7XxNp3p_6P8Y9B3rzq-HcZmtkvyEH15RIS7YTRtPVWf32lVqIRiaPqzLn6upnhuMa9R1A==",
35     "referer": "https://weibo.com/1887344341/L2jya3WQs",
36     "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
37     "x-xsrf-token": "yBO4YQJpwcTtENwqPBhhYOkQ",
38 }
39 
40 url = 'https://weibo.com/ajax/statuses/buildComments?is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&count=10&uid=1887344341&type=feed&maxShowTotal=10'
41 
42 # # 先爬一页
43 # response = requests.get(url=url, headers=headers)
44 # # print(response.json()) # 直接用json接收
45 # # 提取数据,获取五项内容,评论者id,评论者名称,评论时间,点赞人数和评论内容
46 # commentDatas = response.json()['data']
47 # # pprint.pprint(commentDatas)
48 # for item in commentDatas:
49 #     userId = item['user']['id'] # 评论者id
50 #     userName = item['user']['name'] # 评论者名称
51 #     timeCreated = item['created_at']  # 评论时间
52 #     likes = item['like_counts'] # 获赞数
53 #     contentHtml = item['text']  # 评论内容带html标签的
54 #     contentText = item['text_raw']  # 评论内容只有字符串的
55 #     location = item['user']['location'] # 评论者位置
56 #     print(userId, userName, timeCreated, likes, contentText, location, sep="|")
57 # 数据无误,开始多页爬取,
58 page = 1
59 # max_id的参数是从前一页来的,所以先请求第一页,后去到max_id进行循环
60 while page < 30: # 爬1000页
61     # time.sleep(random.uniform(2, 5)) # 随机休眠2-5秒中间的数
62     if page == 1:
63         url = 'https://weibo.com/ajax/statuses/buildComments?is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&count=10&uid=1887344341&type=feed&maxShowTotal=10'
64     else:
65         url = f'https://weibo.com/ajax/statuses/buildComments?flow=0&is_reload=1&id=4705518100941188&is_show_bulletin=2&is_mix=0&max_id={max_id}&count=20&uid=1887344341&type=feed&maxShowTotal=10'
66     # 开始请求网页,从第一页开始
67     print(f'-----------------要爬取的网址为{url}-------------')
68     if page % 16 == 0:
69         time.sleep(10)
70     response = requests.get(url=url,headers=headers)
71     max_id = response.json()['max_id'] # 每次循环之前都会产生一个max_id,第一页的供第二页使用,第二页的供第三页使用,以此类推
72     print(f'---------第{page}页请求到的--max_id为{max_id},供{page+1}页使用!')
73     # 开始提取数据
74     for item in response.json()['data']:
75         userId = item['user']['id']  # 用户id
76         userName = item['user']['name'] # 用户名
77         commentTime = item['created_at'] # 评论时间
78         likes = item['like_counts'] # 评论获赞数
79         contentHtml = item['text'] # 评论内容带html标签的
80         contentText = item['text_raw'] # 评论内容
81         location = item['user']['location'] # 评论地点
82         print(userId, userName, commentTime, likes, contentText, location, contentHtml, sep = " | ")
83         # 开始写入到文本
84         ws.append([userId, userName, commentTime, likes, contentText, location, contentHtml]) # 将内容追加到文本
85     print(f'---------第{page}页的数据保存成功!---------')
86     time.sleep(1)
87     page += 1 # 循环条件,不然一直在第一页
88 wb.save('微博评论.xlsx')
89 wb.close() # 写完关闭文档
90 endTime = time.time() #  程序结束事件
91 
92 print('总共用时:', round((endTime-startTime)/60, 2))

然而并没有什么卵用,因为,评论到达16页以后,就不给数据了。

 于是开始想其他的法子,PC端不给,手机端给不给呢?开干。

https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id_type=0 # 第一页
https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=1185590866447066&max_id_type=0 # 第二页
https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=314915097989517&max_id_type=0 # 第三页
......
https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=4707090586928670&max_id_type=1 # 第17页

通过分析发现,17页的网址变了,它的max_id_type值变了。先爬第一页,看携带哪些参数能获取到值。然后再翻页爬取。从参数发现,这条微博的评论为2423条,那个4万多的应该是下面的耳机评论也计算在内。代码:

 1 """
 2 https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id_type=0 # 第一页
 3 https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=1185590866447066&max_id_type=0 # 第二页
 4 https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=314915097989517&max_id_type=0 # 第三页
 5 ......
 6 https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id=4707090586928670&max_id_type=1 # 第17页
 7 """
 8 import pprint
 9 import openpyxl as op
10 import requests
11 import random
12 import time
13 
14 # 新建excel文档存储数据
15 wb = op.Workbook() # 工作簿
16 ws = wb.create_sheet(index=0) # 工作簿里的第一个工作表
17 ws.cell(row=1, column=1, value='评论者ID') # 第一行第一列评论者id
18 ws.cell(row=1, column=2, value='评论者昵称') # 第一行第二列评论者昵称
19 ws.cell(row=1, column=3, value='评论时间') # 第一样第三列评论时间
20 ws.cell(row=1, column=4, value='评论获赞数') # 第一样第四列评论获赞数
21 ws.cell(row=1, column=5, value='评论内容') # 第一样第五列评论内容
22 
23 # 首先定义参数
24 headers = {
25     "cookie": "SCF=AnKJy3NOK5c-P3XxWYBPzTFGd92WnUEH6LUI_MdzSig02NBwKpa2u00x45GCB3-AOQKJvc_oIAkHIKr7MdST4JE.; SUB=_2A25MbV1zDeRhGedJ61oQ8SjNyTyIHXVvrmM7rDV6PUJbktCOLUfTkW1NVnxxfy_BvTGKBnuuEVnUOYQ8GZaV5mhP; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9WFCIqm7ZokIkH-v5aWq95ji5NHD95QpS05ReK2ceKz7Ws4Dqcjdi--fiK.7iK.pi--fiKy2iK.Ni--fiKL2i-2p; WEIBOCN_FROM=1110006030; _T_WM=65440405732; MLOGIN=1; XSRF-TOKEN=82f68f; M_WEIBOCN_PARAMS=oid%3D4705518100941188%26luicode%3D20000061%26lfid%3D4705518100941188%26uicode%3D20000061%26fid%3D4705518100941188",
26     "mweibo-pwa": "1",
27     "referer": "https://m.weibo.cn/status/L2jya3WQs?jumpfrom=weibocom",
28     "user-agent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36",
29     # "x-xsrf-token": "82f68f",
30 }
31 
32 page = 1
33 while page < 242 + 1:
34     time.sleep(random.uniform(2, 5))
35     print(f'-------------------------------开始爬取评论的{page}页----------------------------------------\n\n')
36     """
37     # 在数据分析确定后的情况下,可以这样写。
38     if page == 1: # 评论首页的url
39         url = 'https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id_type=0'
40     elif 1 < page < 17: # 2-16页的url
41         url = f'https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id={max_id}&max_id_type=0'
42     else: # 第17页后的url
43         url = f'https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id={max_id}&max_id_type=1'
44     """
45     # 在数据分析不确定的时候,也就是可能还有max_id_type变化的情况下,换种写法
46     if page == 1:
47         url = 'https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id_type=0'
48     else:
49         url = f'https://m.weibo.cn/comments/hotflow?id=4705518100941188&mid=4705518100941188&max_id={max_id}&max_id_type={max_id_type}'
50     # 进入循环,请求网页
51     response = requests.get(url=url, headers=headers)
52     # pprint.pprint(response.json())
53     # 每一页的前一页都会返回max_id和max_id_type,初始为第一页,所以进入循环,先获取第一页的
54     max_id = response.json()['data']['max_id'] # 取到max_id
55     max_id_type = response.json()['data']['max_id_type'] # 看参数变化
56     print(f'---第{page}页取得的max_id为:{max_id} ;max_id_type为:{max_id_type} --开始获取数据!---')
57     # 获取评论数据,需要的数据为,评论者id,评论的昵称,评论时间,评论获赞数,评论内容(text和html),评论者相对位置,粉丝数,粉人数,主页
58     commentData = response.json()['data']['data']
59     # pprint.pprint(commentData)
60     for item in commentData:
61         userId = item['user']['id'] # 评论者id
62         userName = item['user']['screen_name'] # 评论者昵称
63         commentTime = item['created_at'] # 评论时间
64         likesCount = item['like_count'] # 获赞数量
65         commentText = item['text'] # 评论内容text格式
66         print(userId, userName, commentTime, likesCount, commentText, sep = " | ")
67     print(f'==============第{page}页数据提取完毕==============\n\n')
68     time.sleep(2)
69     page += 1 # 循环条件
70 
71 
72 wb.save('生育率评论.xlsx') #保存文档
73 wb.close() # 关闭文档

代码运行部分截图:

 从代码运行结果来看,max_id_type在第15页的时候已经变了。但是这样子爬取的话,为了不给服务器造成太大压力,每次循环都要进行休眠,会浪费很多时间,发现多线程然并卵,就不贴代码了。

原文地址:https://www.cnblogs.com/mafu/p/15601892.html