分析ajax接口抓取今日头条

时间:2024-05-22 13:05:37

        抓取ajax网站可以通过分析ajax接口的方式获取到返回的json数据,从而抓取到我们想要的数据,以今日头条为例,如何分析ajax接口,模拟ajax请求爬取数据。

        以今日头条的街拍为例,网页上一页只显示部分数据,查看后续数据需要鼠标下滑,这里我们分析一下它的ajax接口。

分析ajax接口抓取今日头条

打开开发者工具,选择network,点击XHR过滤出来ajax请求,可以看到这里有很多参数,其中一眼能看出来的参数就是keyword,是我们搜索的关键字。接着看它的Preview信息。

分析ajax接口抓取今日头条

Preview信息中可以看到包含有很多data信息,点开可以看到其中包含许多有用的信息,像街拍标题,图片地址。

分析ajax接口抓取今日头条

当鼠标往下滑动,过滤出来的ajax请求会多出来一条,如下所示

分析ajax接口抓取今日头条

可以看到其中的offset参数由0变成了20,细心观察网页可以发现网页显示的信息一页恰好是20条。

分析ajax接口抓取今日头条

这是当鼠标滑动到第三页的时候,可以看到offset参数变成了40,当第一页的时候,offset参数为0,第二页offset参数为20,第三页参数为40。这就不难发现offset参数实际是偏移量,用来实现翻页的参数。那我们就可以通过urlencode方法将这些参数拼接到url后面,发起ajax请求,通过控制传入的offset参数来控制翻页,然后通过response.json()来获取网页返回的json数据。

代码思路:1.分析网页的ajax接口,需要传入哪些数据2.通过urlencode键参数拼接到需要请求的url之后,通过控制offset参数来指定爬取哪一页的内容。3.生成不同页的请求,获取json数据中图片的url信息4.请求图片的url,下载图片5.保存到文件夹。

实际代码

import requests
from urllib.parse import urlencode,urljoin
import os
from hashlib import md5

headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36",
    "X-Requested-With":"XMLHttpRequest"
}

def get_page(offset):
    """
    :param offset: 偏移量,控制翻页
    :return:
    """
    params = {
        "offset":offset,
        "format":"json",
        "keyword":"街拍",
        "autoload":"true",
        "count":"20",
        "cur_tab":"1",
        "from":"search_tab"
    }

    url = "https://www.toutiao.com/search_content/?" + urlencode(params)
    try:
        response = requests.get(url,headers=headers,timeout=5)
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        return None

def get_image(json):
    """
    :param json: 获取到返回的json数据
    :return:
    """
    if json:
        for item in json.get("data"):
            title = item.get("title")
            images = item.get("image_list")
            if images:
                for image in images:
                    yield {
                        "title":title,
                        "image":urljoin("http:",image.get("url")) if type(image) == type({"t":1}) else urljoin("http:",image)
                    }
def save_images(item):
    """
    将图片保存到文件夹,以标题命名文件夹
    :param item: json数据
    :return:
    """
    if item.get("title") != None:
        if not os.path.exists(item.get("title")):
            os.mkdir(item.get("title"))
        else:
            pass
    try:
        response = requests.get(item.get("image"))
        if response.status_code == 200:
            file_path = "{0}/{1}.{2}".format(item.get("title") if item.get("title") != None else "Notitle",md5(response.content).hexdigest(),"jpg")
            if not os.path.exists(file_path):
                with open(file_path,"wb") as f:
                    f.write(response.content)
            else:
                print("Already Downloaded",file_path)
    except requests.ConnectionError:
        print("Failed Download Image")

def main(offset):
    """
    控制爬取的主要逻辑
    :param offset: 偏移量
    :return:
    """
    json = get_page(offset)
    for item in get_image(json):
        print(item)
        save_images(item)

groups = [i*20 for i in range(1,10)]

if __name__ == '__main__':
    for group in groups:
        main(group)


爬取的成果

分析ajax接口抓取今日头条

 

通过分析ajax接口,模拟ajax请求进行抓取相对于selenium模拟来说较简单,但是代码复用性差,因为每个网页的接口都是不同的,所以抓取ajax加载的数据时,使用selenium模拟还是直接抓取接口数据需要小伙伴自己通过实际需要来选择。