python爬虫如何寻找ajax,[Python3爬虫]Ajax请求信息的爬取

本文介绍了如何使用Python爬虫抓取动态加载的内容,以今日头条搜索‘街拍’关键词为例,分析Ajax请求参数,通过模拟请求获取数据。提取图片链接并保存,同时展示了多线程下载的实现,强调了关键参数如offset的调整以及图片存储的逻辑。
摘要由CSDN通过智能技术生成

动态加载页面信息的提取

当我们浏览一个新闻类的网站,例如微博,今日头条,知乎等,由于它的内容极多,当我们搜索某一关键词的信息后,服务器只会向我们返回少量的数据,微博和头条是返回指定数量的数据,当我们再次向下刷新的时候,会再次通过Ajax请求返回指定数目的数据(如果你的网络不好时,会出现一个表示正在加载的小圆圈的动画效果)。知乎是当浏览器的滚动条触底时,再次提取数据。这就产生了一个问题,通过爬虫如何来提取通过Ajax请求动态加载的数据呢?

模拟Ajax请求

这时需要通过Chrome等浏览器的开发者工具,利用Chrome开发者工具的筛选功能筛选出所有的Ajax请求。选择network选项,直接点击XHR分析网页后台向接口发送的Ajax请求,用requests来模拟Ajax请求,那么就可以成功抓取信息了

待爬取网站的Ajax请求的分析

这里选择今日头条来搞事情,通过爬虫来下载头条上街拍关键词的图片,搜索关键词街拍,分析Ajax请求。下面是提取到的Ajax的主要信息

Request URL: https://www.toutiao.com/search_content/?

offset=0&

format=json&

keyword=%E8%A1%97%E6%8B%8D&

autoload=true&

count=20&

cur_tab=1&

from=search_tab

1.分析请求

39e66f2653aa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

pic1.PNG

通过刷新新内容不断的发送Ajax请求,对比不同的几个ajax请求,对比他们的不变的地方和改变的地方,为写程序做好准备。

可以发现每加载一次内容参数offset加20,表示偏移量,每次取20条数据

format是不变的,表示格式是json格式的,

Keyword是我们搜索的关键字

%E8%A1%97%E6%8B%8D& ,,可能是中文的某种加密方式加密后的结果

发现offset加20就可以了,其他参数照搬,因为都是不变的参数

2.分析响应

39e66f2653aa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

pic2.PNG

点击Preview分析响应内容。我们要下载图片,发现图片链接都在image_list里,一篇文章的一张或多张图片都在里面,而外层是data属性,标题在title属性里,这里获取标题名作为文件夹名称进行存储

代码实现

首先,实现方法get_page()来加载单个Ajax请求的结果。其中唯一变化的参数就是offset,所以我们将它当作参数传递,代码实现如下:

import requests

from urllib.parse import urlencode #Python内置的HTTP请求库

def get_page(offset):

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) #拼接URL

try:

r = requests.get(url)

if r.status_code == 200:

return r.json() # 返回json格式的响应内容

except:

return None

urllib库

Python内置的HTTP请求库,通常我们使用的是功能更为强大的requests库,用到urllib的parse工具模块,提供了许多URL处理方法,比如拆分、解析、合并等。用urlencode()方法构造请求的GET参数。

接下来,再实现一个解析方法:提取每条数据的image_list字段中的每一张图片链接,将图片链接和图片所属的标题一并返回,同时构造一个生成器。实现代码如下:

def get_images(jsondata):

if jsondata.get('data'):

for item in jsondata.get('data'):

title = item.get('title')

images = item.get('image_list')

for image in images:

yield {

'image' : image.get('url'),

'title' : title

}

接下来,实现一个保存图片的方法save_image(),其中item就是前面get_images()方法返回的一个字典。在该方法中,首先根据item的title来创建文件夹,然后请求这个图片链接,获取图片的二进制数据,以二进制的形式写入文件。图片的名称可以使用其内容的MD5值,这样可以去除重复。

def save_image(item):

if not os.path.exists(item.get('title')):

os.mkdir(item.get('title'))

try:

image_url = item.get('image')

print(image_url)

r = requests.get('http:'+image_url)

if r.status_code == 200:

file_path = '{0}/{1}.{2}'.format(item.get('title'),md5(r.content).hexdigest(),'jpg')

if not os.path.exists(file_path):

with open(file_path,'wb') as f:

f.write(r.content)

else:

print('Already Downloaded', file_path)

except:

print('Faild to Save Image')

最后,构造一个offset数组,遍历offset,提取图片链接,并将其下载:

def main(offset):

jsondata = get_page(offset)

for item in get_images(jsondata):

print(item)

save_image(item)

num_start = 1

num_end = 20

if __name__ == '__main__':

pool = Pool()

num = ([x * 20 for x in range(num_start,num_end + 1)])

pool.map(main,num)

pool.close()

pool.join()

整体代码

import requests

from urllib.parse import urlencode

import os

from hashlib import md5

from multiprocessing.pool import Pool

def get_page(offset):

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:

r = requests.get(url)

if r.status_code == 200:

return r.json()

except:

return None

def get_images(jsondata):

if jsondata.get('data'):

for item in jsondata.get('data'):

title = item.get('title')

images = item.get('image_list')

for image in images:

yield {

'image' : image.get('url'),

'title' : title

}

def save_image(item):

if not os.path.exists(item.get('title')):

os.mkdir(item.get('title'))

try:

image_url = item.get('image')

r = requests.get('http:'+ image_url)

if r.status_code == 200:

file_path = '{0}/{1}.{2}'.format(item.get('title'),md5(r.content).hexdigest(),'jpg')

if not os.path.exists(file_path):

with open(file_path,'wb') as f:

f.write(r.content)

else:

print('Already Downloaded', file_path)

except:

print('Faild to Save Image')

def main(offset):

jsondata = get_page(offset)

for item in get_images(jsondata):

print(item)

save_image(item)

num_start = 1

num_end = 20

if __name__ == '__main__':

pool = Pool()

num = ([x * 20 for x in range(num_start,num_end + 1)])

pool.map(main,num)

pool.close()

pool.join()

这里定义了分页的起始页数和终止页数,分别为num_start和num_end,还利用了多线程的线程池,调用其map()方法实现多线程下载

运行效果

39e66f2653aa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

pic3.PNG

关于作者

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值