共计 3960 个字符,预计需要花费 10 分钟才能阅读完成。
在浏览社交媒体时,咱们所看的内容好像是无穷无尽的。
咱们经常滑动到页面底端,认为没有内容了,却发现新的内容又一下子刷新进去。内容越滑越多,这种数据被称作列表流数据。
乏味的是,当页面一直为咱们提供新的内容时,网页却还是原来的网页——URL 并没有扭转。这是怎么回事?
1 Ajax
在同一个页面中,网页是如何源源不断的展示新内容的呢?
如果关上浏览器的开发者模式,当咱们滑动到页面底端时,咱们能够在“网络”选项卡中观测到一些新生成的 xhr 类型条目。这类条目中蕴含的就是 Ajax 申请。依据崔庆才老师的介绍:
Ajax,全称为 Asynchronous JavaScript and XML,即异步的 JavaScript 和 XML。它不是一门编程语言,而是利用 JavaScript 在保障页面不被刷新、页面链接不扭转的状况下与服务器替换数据并更新局部网页的技术。
对于传统的网页,如果想更新其内容,那么必须要刷新整个页面,但有了 Ajax,便能够在页面不被全副刷新的状况下更新其内容。在这个过程中,页面实际上是在后盾与服务器进行了数据交互,获取到数据之后,再利用 JavaScript 扭转网页,这样网页内容就会更新了。
简略来说, 当咱们向下滑动到页面底端,JavaScript 会向网页后盾的服务器发送一个申请,通知服务器咱们想要更多的内容。服务器返回相应的响应内容,JavaScript 又对响应内容(不论是 HTML 格局,还是 JSON 格局)进行了解析,并渲染成为咱们看到的新内容。
2 列表流数据的爬取:以微博为例
理解了列表流数据是如何源源不断产生的后,咱们就有了获取这种数据的思路:模仿 JavaScript 向网页服务器发送 Ajax 申请,并解析获取到的响应数据。
上面来演示爬取过程——以爬取微博个性化举荐内容为例。
2.1 察看 Ajax 申请
咱们找到上文提到的 xhr 文件,点击它,咱们能够看到文件蕴含的标头信息。其中相干的信息包含:
- 申请 URL:如果你察看多条 xhr 条目的话,你会发现它们的 URL 简直齐全一样,惟一不同之处在于 max_id 的值,从 1 开始,每从底部刷新一次,新的 xhr 条目标 max_id 的值就会减少 1。
- 申请办法
- 状态代码
- 申请标头中的 cookie
- 申请标头中的 user-agent
- 申请标头中的 x-requested-with,它的值为 XMLHttpRequest,这标记了该条申请是 Ajax 申请
除了标头以外,咱们还能够察看到该条 Ajax 申请的预览,这是一个 JSON 文件。
能够看到,该条申请中蕴含 10 条内容,如果深刻察看一条内容外部,咱们能够找到这条内容对应的微博信息,包含微博 id、公布用户、微博文字内容、微博图片内容、公布该条微博的 IP 地址信息等。
2.2 爬取 Ajax 申请获取的 JSON 数据
当初咱们能够尝试爬取上述数据了。首先导入咱们所需的包,并定义一些后续用失去的变量:
from urllib.parse import urlencode
import requests
from pyquery import PyQuery as pq
base_url = 'https://weibo.com/ajax/feed/hottimeline?' # 本我的项目要爬取的 url 都是以此为结尾的
headers = {
'User-Agent': '你的 User-Agent', # 点击你要爬取的 xhr 文件,在标头中能够找到相干信息。'X-Requested-With': 'XMLHttpRequest',
'Cookie': '你的 Cookie'
}
咱们来构建一个函数,用于返回咱们要发送模仿申请的 URL:
def get_hottimeline_url(max_id):
'''返回一个 xhr 类型"hottimeline (热榜工夫流)" 的 url。:param max_id: 每个 hottimeline url 中非凡的 max_id (1, 2, 3...)
'''params = {'refresh':'2','group_id':' 你 URL 中的 group_id','containerid':' 你 URL 中的 group_id containerid','extparam':'discover%7Cnew_feed','max_id': max_id, # URL 中只有该值是变动的'count':'10'}
url = base_url + urlencode(params, safe='%') # 此处指明 safe 参数,使 "%" 不被本义为 "%25",不然会拼接成谬误的 URL
return url
接下来,咱们像获取动态页面的数据一样,通过 request 发送申请,获取 JSON 数据:
def get_response_json(url):
'''返回一个 url 的 json 文件。'''
response = requests.get(url, headers=headers)
json = response.json()
return json
2.3 解析 JSON 数据
获取到 JSON 数据后,咱们须要对数据进行解析,获取咱们所需的信息。一个 URL 能返回 10 条微博内容,咱们心愿能循环失去每一条微博内容的数据,存为一个字典。再将这个字典,存入微博内容组成的列表中。
在获取一条微博的文本内容时,咱们须要留神,当这条微博的文本内容过长时,文本段会被折叠。如果咱们想看到残缺的内容,须要在浏览器界面点击“开展”按钮,这使得咱们无奈在现有的 JSON 数据中取得残缺的文本数据。然而,当咱们点击开展时,能够看到开发者模式的网络选项卡中,又多出了名为“longtext?id=xxxxxxxxxx”的 xhr 条目,咱们能够通过该条目标 URL 获取到残缺的长文本数据。
def parse_hottimeline(list_recommendation, json):
'''解析一条 hottimeline 的 json 文件,并将蕴含的 10 条热榜举荐内容追加到内容列表中。'''
for item in json.get('statuses'):
weibo = {} # 创立一个长期的用于保留一条微博信息的字典
# user information
user_info = item.get('user')
weibo['user_id'] = user_info.get('id') # 发布者 id
weibo['user_name'] = user_info.get('screen_name') # 发布者昵称
# weibo information
weibo['id'] = item.get('id') # 微博 id
weibo['isLongText'] = item.get('isLongText') # 该变量为 True 时,这个微博的文本为长文本(文本段会被折叠)weibo['mblogid'] = item.get('mblogid') # 能够通过该变量,索引到存有长文本的 JSON 文件的 URL
if weibo['isLongText'] is True:
url = "https://weibo.com/ajax/statuses/longtext?id=" + weibo['mblogid']
json_longtext = get_response_json(url)
weibo['text'] = json_longtext.get('data').get('longTextContent')
else:
weibo['text'] = pq(item.get('text')).text()
weibo['pic_num'] = item.get('pic_num') # 该条微博蕴含的图片数
weibo['pic'] = [] # 用于保留该条微博图片的 url
if weibo['pic_num'] > 0:
pic_dict = item.get('pic_infos')
for pic in pic_dict:
pic_url = pic_dict[pic]['original']['url']
weibo['pic'].append(pic_url)
else:
pass
weibo['attitudes'] = item.get('attitudes_count') # 点赞数
weibo['comments'] = item.get('comments_count') # 评论数
weibo['reposts'] = item.get('reposts_count') # 转发数
region = item.get('region_name') # 公布时的 IP 地址
if region is None:
weibo['region'] = region
else: weibo['region'] = region.strip('公布于')
print(weibo)
list_recommendation.append(weibo) # 将解析出的一条微博数据,退出一个列表中
2.4 存储数据
咱们曾经实现了页面底部刷新数据的 URL 获取、模仿申请、解析数据的性能。最初,咱们将新建一个列表,将每条微博信息存储进去。主函数的代码如下:
if __name__ == '__main__':
list_recommendation = []
for max_id in range(1, 11): # 模仿爬取 10 次刷新后果,最终能获取到 100 条个性化举荐热门微博数据
hottimeline_url = get_hottimeline_url(max_id)
print('hottimeline_url =', hottimeline_url)
response_json = get_response_json(hottimeline_url)
parse_hottimeline(list_recommendation, response_json)
参考
- Python3 网络爬虫开发实战 -6 Ajax 数据爬取(崔庆才)
注:转载请注明出处。