最近阅读了崔庆才写的《Python3网络爬虫开发实战》,系统地学习一下利用Python写网络爬虫。由于这本书出版时间是2018年,很多书中案例涉及的网站已经改版,基本上每个案例都需要自己再研究一下网站改版后新的结构来爬取数据。这篇博文就来介绍一下如何爬取一下新浪微博用户的微博信息和下载该用户的微博图片,其中涉及到的技术包括Ajax数据爬取,Python和MongoDB的交互以及windows下python的多进程编程。
使用Ajax请求爬取用户微博信息并存储到后端MongoDB
关于基础的网页前端各个节点的结构,http的get和post请求,requests库中的get函数用法,普通网页header请求头的构建,Beautiful Soup和pyquery解析库的使用这里不做过多介绍,对这方面不是很了解的同学建议先去看一下《Python3网络爬虫开发实战》中的前四章来详细了解一下。这里简要介绍一下什么是Ajax加载,它是一种异步的数据加载方式,原始的页面最初不会包含某些数据,原始页面加载完之后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现到网页上,这其实就是发送了一个Ajax请求,本质上来讲Ajax是利用了JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。
以我的移动端新浪微博页面为例:https://m.weibo.cn/u/6163257669,选择Network下面的XHR选项卡,点击刷新页面之后,在下拉的过程中会发现有getIndex?开头的请求冒出来,这就是Ajax请求,构造Ajax请求主要是提供Requests header和Query String Parameters中的参数。
再看一下该请求返回的数据Previews,如下图所示,其中cards中的绝大部分card对应的是每条微博,点开一个card,若有mblog字段代表这条card对应的是一条微博,mblog字段下面不同字段包含这条微博的所有信息。我们这次主要是爬取每条微博的id,text,attitudes,comments,reposts这几个属性。然后将信息写入MongoDB中,windows下MongoDB的安装可以参考https://www.runoob.com/mongodb/mongodb-window-install.html,为了能够之直接在命令行通过mongo命令启动数据库命令行,可以将mongo安装目录(例如C:\Program Files\MongoDB\Server\4.2\bin)添加到相应的系统环境变量。
关于构造请求的query string parameters参数,其中有一个since_id,这个代表每次Ajax加载时对应的第一条微博id,我们遍历所有微博的方法就是从该用户第一条微博id(有些用户页面上的第一条微博是置顶的,注意不要选该微博作为第一条微博,需要找时间上最晚发的微博)开始作为起始的since_id,返回的数据包含之后的十条card,然后再以最后一个card作为起始的since_id再爬取后续的十条card(下一次返回的结果中要去掉第一条,防止重复爬取该条微博),以此类推最终遍历完所有微博。最终爬取的脚本如下所示:
#author:xfxy
#time:2020/04/18
from urllib.parse import urlencode
from pyquery import PyQuery as pq
import requests
import time
import pymongo
base_url='https://m.weibo.cn/api/container/getIndex?'
def get_all_weibo(since_id): #该函数通过提供since_id参数来爬取cards
if since_id==None:
return None
#请求头的构建
headers={
'Referer': 'https://m.weibo.cn/u/6163257669?from=myfollow_all&is_all=1&sudaref=login.sina.com.cn',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.4040.400',
'X-Requested-With': 'XMLHttpRequest',
}
#Query string parameters的构建
params={
'from': 'myfollow_all',
'is_all': '1',
'sudaref': 'login.sina.com.cn',
'type': 'uid',
'value': '6163257669', #这是我微博的id,如果想爬取某个用户的微博,需要更改value,containerid,headers中的Referer
'containerid': '1076036163257669',
'since_id': since_id,
}
url=base_url+urlencode(params) #通过Query string parameters构造请求url
r=requests.get(url,headers=headers)
return r.json().get('data').get('cards')
items=get_all_weibo('4494845651530130') #since_id为我第一条微博的id
client = pymongo.MongoClient(host='localhost',port=27017) #建立和MongoDB的链接
db=client.weibo #建立数据库weibo
collection=db.xfxy #建立键值对集合collections
while(1): #循环退