Python爬虫学习笔记 1-3:爬取ajax加载网页

Published On 2019/08/11 Sunday, Singapore

本节以爬取Joyenjoye关注的人为例,讲解如何爬取ajax或者javascript加载的网页。

本文为Datacatsle Python爬虫(入门+进阶)课程学习笔记。


网页源码的组成一般来说为html, css 和javascript。 当数据是是直接写在hmtl文件时,可以使用python爬虫学习笔记1-2中的方法,直接请求网页url获取html文件,解析得到数据。但是大多情况下,数据不会被直接写在html文件中,而是通过javascript来进行加载。这时不再能够通过网页URL直接请求数据,而需要先寻找数据的真实URL,再进行请求。

那么如何判断数据是否为javascript加载呢? 在谷歌浏览器中,我们可以在网站site setting中禁用javascript,然后观察网页上的数据是否能正常显示。如果能正常显示,说明数据是直接写在html文件中的。反之,数据是通过javascript加载的。



寻找真实请求

确定数据为javascript进行加载以后, 我们使用谷歌开发者工具对网页请求进行分析,寻找数据的真实请求。

现在我们来分析Joyenjoye关注的人的真实请求,执行以上步骤我们可以看到下图所示:

<

在preview中可以看到其中的数据正是页面中看到的数据。现在我们点击header取获取真实请求url.

<

到此为止,我们找到了Joyenjoye关注的人的真实请求URL为

https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=20&limit=20.



翻页参数

通常来讲,需要进行翻页来获取完整数据。这时候我们需要知道真实请求中的是控制翻页的参数。

<

点击不同页面2,3,4,找到对应页面的真实请求连接进行对比如下:

'https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=20&limit=20.'

'https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=40&limit=20.'

'https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset=60&limit=20.'

对比不同请求发现,只有offset的参数分别为20,40,60,可知其为翻页参数。 另一种方法是去直接看几个真实请求header下的querying string parameter有什么不同。改变的paremeter一般来说即为翻页参数。



添加请求头

如果直接用request去请求前面的找到的URL,具体code如下,会返回bad request 404。

url ='https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data\
%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed\
%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset={}&limit=20'.format(i*20)
response = requests.get(url)
print(response.text)

这是由于网站反爬虫的原因。该问题可以通过在请求时添加请求头(header)来解决。请求头信息承载了关于客户端浏览器、请求页面、服务器等相关的信息,用来告知服务器发起请求的客户端的具体信息。

请求头的信息可以通过google浏览器在Inspect > Network > Header > Request Headers 获取。 不同网站的反爬虫对header的校验不同,经测试知乎仅需要提供user-agent即可。

headers={
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
url ='https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data\
%5B*%5D.answer_count%2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed\
%2Cis_following%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset={}&limit=20'.format(i*20)
response = requests.get(url,headers = headers)
print(response.text)


定义函数实现翻页爬取

成功实现爬取单页数据以后,我们定义函数get_user_data来爬取多页数据,并添加请求时间间隔以免由于爬取太频繁给服务器造成负担。最后将获取的数据保存在csv文件中。

import requests
import pandas as pd
import json
import time

headers={
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}

user_data = []

def get_user_data(page):
    for i in range(page):
        print('当前正在爬取第{}页'.format(i+1))
        url ='https://www.zhihu.com/api/v4/members/joye-lee-29/followees?include=data%5B*%5D.answer_count\
        %2Carticles_count%2Cgender%2Cfollower_count%2Cis_followed%2Cis_following\
        %2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset={}&limit=20'.format(i*20)
        response = requests.get(url,headers = headers)
        data=json.loads(response.text)
        user_data.extend(data['data'])
        time.sleep(1)

get_user_data(7)
df = pd.DataFrame.from_dict(user_data)
df.to_csv('output/user_data.csv')





💚 Back to Home