既不鲁棒又不高效的辣鸡爬虫
微博爬虫
最近的任务需要研究对话中的post-response pair,虽然之前也找了一些数据,但是对于现在的需求还是太少了。然后两三周前得知idea被隔壁的童鞋抢发的消息,就要来了paper看了一下,从中获取灵感决定从微博上爬一点数据下来(你的思路到底有多狭窄…)。好啦我也承认之前不敢爬微博是因为它反爬虫反的太厉害了QAQ。。。
不过最后还是鼓起勇气去爬了微博…因为这种全是动态的网页还是第一次搞,查了一下资料发现可以根据其ajax来爬取信息。基本上就是你给微博的服务器发一个request,然后它就给你返回一个json信息,根据这个json信息你就可以知道这条微博的内容是什么,回帖有哪些。同时为了处理的简单,选择了移动版的网页爬取。(一般来说移动版的数据都比pc版的好爬)
具体步骤是这样:先选择一个爬虫起点uid(每个微博用户用一个唯一的uid标识),然后用https://m.weibo.cn/api/container/getIndex?
这个url构造request(具体情况还是去看代码),这里我爬了其前10页的微博。解析器返回的json,发现里面有个cards,cards下面有每一条微博的具体地址(即每条微博的单独标识id),再用https://m.weibo.cn/api/comments/show?id=
这个url构造request即可得到每个微博下面的评论。把第一条评论内容找出来,和微博内容构成一个 post-response pair,就大功告成了。然后把每个评论的人的id加入待爬id池,就可以开心的一直循环了~
然后谈谈问题:
第一个无疑就是封ip了,封了ip这个程序就直接死掉了。解决办法也不是没有,一个是可以sleep几秒再爬,一个是去找免费ip代理。但是这样都太慢了,现在爬微博本身就很慢,再处理这个东西就更慢了。
第二个是会有个json解析错误。现在不知道具体是为什么,而且我明明都加了try语句的,也不知道为什么会有错,还是再看看吧。
附上代码:
import time
from urllib.parse import urlencode
import requests
# from pyquery import PyQuery as pq
start_id = '1904769205'
crawl_list = [start_id]
crawl_index = 0
crawl_set = set()
crawl_set.add(start_id)
all_pr_pair = []
base_url = 'https://m.weibo.cn/api/container/getIndex?'
headers = {
'Host': 'm.weibo.cn',
'Referer': 'https://m.weibo.cn/u/1904769205',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}
def get_page(page, val):
params = {
'type': 'uid',
'value': val,
'containerid': '107603' + val,
'page': page
}
url = base_url + urlencode(params)
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
except requests.ConnectionError as e:
print('Error', e.args)
def my_parse_json(json):
if json:
pr_pair = []
try:
items = json.get('data').get('cards')
except Exception as e:
print(e)
print('the json has no crads')
return pr_pair
for item in items:
try:
mblog = item.get('mblog')
post = mblog.get('text')
# bid = mblog.get('bid')
rid = mblog.get('id')
# new_header = {
# 'Host': 'm.weibo.cn',
# 'Referer': 'https://m.weibo.cn/u/' + bid,
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
# 'X-Requested-With': 'XMLHttpRequest',
# }
new_url = 'https://m.weibo.cn/api/comments/show?id=' + rid + '&page=1'
# new_res = requests.get(new_url, headers=new_header)
new_res = requests.get(new_url)
all_data = new_res.json().get('data').get('data')
# print("ddd")
response = all_data[0].get('text')
pr_pair.append((post, response))
for data in all_data:
usr_id = data.get('user').get('id')
usr_id = str(usr_id)
if usr_id in crawl_set:
pass
else:
crawl_set.add(usr_id)
crawl_list.append(usr_id)
# print(str(usr_id))
# input()
except Exception as e:
# print(e)
pass
return pr_pair
# json = get_page(1, '2830678474')
# pr = my_parse_json(json)
fout = open("res.txt", 'w', encoding='utf-8')
start = time.time()
total_len = 0
while crawl_index < len(crawl_list) and crawl_index < 100000:
# for every one, at most crawl 10 pages
for i in range(1, 11):
json = get_page(i, crawl_list[crawl_index])
pr = my_parse_json(json)
# print(len(pr))
try:
for pair in pr:
fout.write(pair[0] + '\n')
fout.write(pair[1] + '\n')
fout.write('\n')
# all_pr_pair.extend(pr)
total_len += len(pr)
except Exception as e:
pass
crawl_index += 1
if crawl_index % 1000 == 0:
end = time.time()
print(crawl_index, total_len, end - start)
# print(crawl_index, len(all_pr_pair))
fout.close()