乐趣区

关于爬虫:爬虫越滑越多的动态网页列表流数据通过-Ajax-获取微博个性化推荐内容

在浏览社交媒体时,咱们所看的内容好像是无穷无尽的。

咱们经常滑动到页面底端,认为没有内容了,却发现新的内容又一下子刷新进去。内容越滑越多,这种数据被称作列表流数据。

乏味的是,当页面一直为咱们提供新的内容时,网页却还是原来的网页——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 数据爬取(崔庆才)

注:转载请注明出处。

退出移动版