爬取【ajax+json】异步加载的网站

时间:2021-06-16 12:28:34

@导入类库

import requests
from lxml import etree
import json
import time

@请求地址和请求头

# 请求头,用于伪装客户端浏览器,可由抓包获取
header_base = {
    'Connection': 'keep-alive',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',
    'Upgrade-Insecure-Requests': '1',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
}

# 首页 URL
url_str = 'https://www.douyu.com/directory/all'

@发起请求,并获得html文档的页面元素树

# 获取首页信息
response = requests.get(url=url_str, headers=header_base)
# print(response.text)
# print(response.status_code)

# 获得页面的元素树
html = etree.HTML(response.text)

@解析首页信息

# 通过xpath提取房间信息:播主和在线人数
info_list = html.xpath(
    "//ul[@id='live-list-contentbox']//span[@class='dy-name ellipsis fl']/text() \ | //ul[@id='live-list-contentbox']//span[@class='dy-num fr']/text()"
)

# 播主昵称
host_names = info_list[0]
print('first_name : ', host_names)

# 打印所有房间信息
for info in info_list:
    print(info)

@点击首页底部的分页页码时,地址栏不会发生变化,由此我们知道该网站的分页信息是通过ajax做异步加载的
爬取【ajax+json】异步加载的网站

# 这里我们发现当点击第二页时,浏览器的地址栏并没有发生变化
# 无法直接从页面获取页码,因为页码是通过JS生成的
# page_num = html.xpath("//a[@class='shark-pager-item']/text()")
# print('page_num : ', page_num)

@知道了分页数据的加载地址之后,我们逐页发起请求,获取其json数据,并做分析和提取

# 该网站的分页数据是通过ajax异步加载的(无法直接从浏览器的地址栏获取其页面的URL)
# 需要借助抓包工具或页面控制台获得ajax异步请求所发送请求的url
page = 1
while True:

    # 不断爬取下一页
    page += 1

    # 通过抓包分析获得的分页地址
    url_str = 'https://www.douyu.com/gapi/rkc/directory/0_0/' + str(page)
    print(url_str)

    # 请求房间信息
    response = requests.get(url=url_str, headers=header_base)
    # print(response.text)

    # 从第二页开始,数据以json格式加载,因此先将文本转换为json
    info_json = json.loads(response.text)
    # print(type(info_json['data']['rl']))

    # 当请求的页码大于最大页码时返回的是第一页数据
    # 我们以此作为循环退出条件
    print('========', info_json['data']['rl'][0]['nn'],"==========")
    if host_names == info_json['data']['rl'][0]['nn']:
        break

    # 分析json信息,循环获取每个直播房间的信息
    for one_info in info_json['data']['rl']:

        # 获取主播名称
        host = one_info['nn']

        # 获取直播在看人数
        onlines = one_info['ol']

    # 睡一会再接着爬下一页,以免请求过于频繁被反爬
    time.sleep(2)

@爬取效果
爬取【ajax+json】异步加载的网站

@完整代码

import requests
from lxml import etree
import json
import time

# 请求头,用于伪装客户端浏览器,可由抓包获取
header_base = {
    'Connection': 'keep-alive',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',
    'Upgrade-Insecure-Requests': '1',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
}

# 首页 URL
url_str = 'https://www.douyu.com/directory/all'

# 获取首页信息
response = requests.get(url=url_str, headers=header_base)
# print(response.text)
# print(response.status_code)

# 获得页面的元素树
html = etree.HTML(response.text)

# 通过xpath提取房间信息:播主和在线人数
info_list = html.xpath(
    "//ul[@id='live-list-contentbox']//span[@class='dy-name ellipsis fl']/text() \ | //ul[@id='live-list-contentbox']//span[@class='dy-num fr']/text()"
)

# 播主昵称
host_names = info_list[0]
print('first_name : ', host_names)

# 打印所有房间信息
for info in info_list:
    print(info)

# 这里我们发现当点击第二页时,浏览器的地址栏并没有发生变化
# 无法直接从页面获取页码,因为页码是通过JS生成的
# page_num = html.xpath("//a[@class='shark-pager-item']/text()")
# print('page_num : ', page_num)

# 该网站的分页数据是通过ajax异步加载的(无法直接从浏览器的地址栏获取其页面的URL)
# 需要借助抓包工具或页面控制台获得ajax异步请求所发送请求的url
page = 1
while True:

    # 不断爬取下一页
    page += 30

    # 通过抓包分析获得的分页地址
    url_str = 'https://www.douyu.com/gapi/rkc/directory/0_0/' + str(page)
    print(url_str)

    # 请求房间信息
    response = requests.get(url=url_str, headers=header_base)
    # print(response.text)

    # 从第二页开始,数据以json格式加载,因此先将文本转换为json
    info_json = json.loads(response.text)
    # print(type(info_json['data']['rl']))

    # 当请求的页码大于最大页码时返回的是第一页数据
    # 我们以此作为循环退出条件
    print('========', info_json['data']['rl'][0]['nn'],"==========")
    if host_names == info_json['data']['rl'][0]['nn']:
        break

    # 分析json信息,循环获取每个直播房间的信息
    for one_info in info_json['data']['rl']:

        # 获取主播名称
        host = one_info['nn']

        # 获取直播在看人数
        onlines = one_info['ol']

    # 睡一会再接着爬下一页,以免请求过于频繁被反爬
    time.sleep(2)

print('OVER !!!')