python爬虫—分析Ajax请求对json文件爬取今日头条街拍美图

python爬虫—分析Ajax请求对json文件爬取今日头条街拍美图html

前言

本次抓取目标是今日头条的街拍美图,爬取完成以后,将每组图片下载到本地并保存到不一样文件夹下。下面经过抓取今日头条街拍美图讲解一下具体操做步骤。python

1、准备

网站:
https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D
环境:anaconda3-spyderweb

2、分析网页

一些网页直接请求获得的HTML代码其实并无咱们在网页中看到的内容,这是由于一些信息经过Ajax加载了,而后经过JavaScript渲染生成的,这时就须要经过分析网页的请求来获取想要爬取的内容。例如我进入街拍这个页面下,右键查看网页源代码,再返回街拍页面一直向下拉动,街拍页面会变换出现不一样的内容和图片,再右键查看源代码,发现源代码和第一次咱们查看的源代码是同样的,没有发生变化,而且源代码很短。以下所示:
在这里插入图片描述算法

在这里插入图片描述因此重点来了,想看数据在哪,咱们如何定位呢?
一、Chrome查看的Ajax请求
打开开发者工具,查看全部的网络请求
在这里插入图片描述
二、查看URL内的数据
在这里插入图片描述
咱们再data下面可以找到title
在这里插入图片描述还可以找到image_list,包含图片的连接,也就是咱们要爬取的图片url。所以,咱们只须要将列表中的url字段提取出来并下载就ok了,每一组图都创建一个文件夹,文件夹的名称就为组图的标题。json

在这里插入图片描述三、请求URL和Headers信息找规律
属性位置的定位找到了之后,咱们还需分析一下URL的变化规律。点击headers,观察它的请求URL和Headers信息,查看第一个headers,红框里确实包含不少参数
在这里插入图片描述这么多参数不用蒙圈,由于都在下面显示好了api

在这里插入图片描述
如今咱们查看第二个headers的url参数,发现有一个参数发生了变化,offest由0变成20网络

在这里插入图片描述咱们再观察第三个headers的url的参数
在这里插入图片描述offest变成了40,因此不难发现,除了offest之外,其余参数都是不变的,只有offest发生变化,而且变化的规律为0、20、40、60…这样的规律。因此说这个offset值就是偏移量,进而能够推断出页面每加载一次,获取的数据条数为20。所以,咱们能够用offset参数来控制数据分页,经过这个接口批量获取数据了,而后解析。app

3、代码实现

一、导包

第一个包,主要目的是经过from urllib.parse import urlencode构造完整的URL。Urllib是python内置的HTTP请求库,urllib.parse url解析模块。
第四个os模块主要和文件路径相关联
第五个把字符串换成MD5的方法python爬虫

from urllib.parse import urlencode
import requests
import json
import os
from hashlib import md5

二、首先获取请求并返回解析页面

定义一个函数get_page()来加载单个Ajax请求的结果。由上述分析可知惟一变化的参数就是offset,因此咱们将它看成参数传递进来。若是访问成功,状态码为200,最后返回的就是json格式的解析页面
在这里插入图片描述svg

def get_page(offest):#获取请求并返回解析页面
    params = { 
 
  
        'aid': '24',
        'app_name': 'web_search',
        'offset': offest,
        'format': 'json',
        'keyword': '街拍',
        'autoload': 'true',
        'count': '20',
        'en_qc': '1',
        'cur_tab': '1',
        'from': 'search_tab',
        'pd': 'synthesis',
        'timestamp': '1602563085392',
        '_signature': 'LfFmxgAgEBBOl5xAwmvANy3wJ9AAHJ7m7oodN5ACyp.Hg2l3uBmMDqDDDN6rWnqjaV0akHlvj327I-FN9Xrxz9FT7hdlRtmAVGnGPJlX5zzT8tcamaIq51QEsm2ry1w0eu0'
        }
    url = base_url + urlencode(params)
    try:
        rq = requests.get(url,headers = headers)
        if rq.status_code == 200 :
            #print(rq.json())
            return rq.json()
    except rq.ConnectionError as e:
        print('程序错误',e.args)

三、解析出data下的title和image_list的url

html为上面函数解析出来的json页面信息,咱们做为参数传进这个函数中,需先找到html下的data,再从data下找title和image_list.

def get_images(html):
    if html.get('data'):  #获得data下的所有内容
        for item in html.get('data'): #用item循环每一条
            #这里须要判断image_list是否为空
            title = item.get('title')
            if 'image_list' in item and item['image_list'] != []:
                images=item['image_list']
                for image in images:
                    yield{ 
 
  
                        'image': image.get('url'),
                        'title': title
                        }#返回一个字典

四、建文件夹存图片

item为data下的全部内容
若是文件夹不存在,那么就os.mkdir新建一个以title为名的文件夹,item.get(‘title’)中括号里的title是上面那个函数返回的
‘image’: image.get(‘url’),
‘title’: title
把它定义成了title
若是咱们成功访问了图片的连接地址,那么就能够图片命名了,这里用了哈希算法(我下去还得好好再理解一下)。接下来若是文件夹里面没东西,就打开文件夹写入图片response.content。

def save_image(item):
    #os.path模块主要用于文件的属性获取,exists是“存在”的意思,
    #因此顾名思义,os.path.exists()就是判断括号里的文件夹'picture'+str(offset)是否存在的意思,括号内的能够是文件路径。
    if not os.path.exists(item.get('title')):#判断当前文件夹下是否有该文件
        os.mkdir(item.get('title'))#若是不存在就建立该文件夹
    try:
        response=requests.get(item['image']) #get函数获取图片连接地址,requests发送访问请求,上面那个字典
        if response.status_code==200:
            file_path='{0}/{1}.{2}'.format(item.get('title'),md5(response.content).hexdigest(),'jpg')
            # md5摘要算法(哈希算法),经过摘要算法获得一个长度固定的数据块。将文件保存时,经过哈希函数对每一个文件进行文件名的自动生成。
            # md5() 获取一个md5加密算法对象
            # hexdigest() 获取加密后的16进制字符串
            if not os.path.exists(file_path):
                with open(file_path,'wb') as f:
                    f.write(response.content)
                print('Downloaded image path is: ', file_path)
            else:
                print('Already Dowloaded',file_path)
    except requests.ConnectionError:
        print('Failed to Save Image')

五、主函数调用

先存如两页的图片

if __name__ == '__main__':
    base_url = 'https://www.toutiao.com/api/search/content/?'   
    headers = { 
 
  
        'referer': 'https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
        'x-requested-with': 'XMLHttpRequest'
        }
    for offest in range(0,40,20):
        html = get_page(offest)
        a=get_images(html)
        for item in a:
            save_image(item)
    for i in a:
         print(i)

4、结果展现

我把存入的过程依次输出
在这里插入图片描述查看文件!在这里插入图片描述在这里插入图片描述

在这里插入图片描述