ajax抓取网页内容(以今日头条为例分析Ajax请求抓取网页数据(一) )

优采云 发布时间: 2021-11-13 13:20

  ajax抓取网页内容(以今日头条为例分析Ajax请求抓取网页数据(一)

)

  以今日头条为例,分析Ajax请求获取网页数据。这次把今日头条街拍关键词对应的图片抓起来保存到本地

  一、分析

  打开今日头条首页,在搜索框中输入街拍这个词,打开开发者工具,发现浏览器显示的数据不在源码中。这样我们就可以初步判断这些内容是由

  Ajax 被加载,然后使用 JavaScript 呈现。

  

  切换到 XHR 过滤选项卡以查看其 Ajax 请求。点击其中一个进入,进入数据展开,发现其中一个标题字段对应的值正是页面上某条数据的标题。看其他数据,刚好是一一对应的,说明这些数据确实是Ajax加载的。

  

  这次的目的是捕捉图像内容。数据中的每个元素都是一个文章,元素中的image_list字段收录了文章的图片内容。它采用列表的形式,其中收录所有图片的列表。我们只需要下载列表中的url字段,并为每个文章创建一个文件夹,文件夹名就是文章的标题。

  

  在使用 Python 爬取之前,您还需要分析 URL 的规则。切换到标题选项卡以查看标题信息。如您所见,这是一个 GET 请求。请求的参数有:aid、app_name、offset、format、keyword、autoload、count、en_qc、cur_tab、from、pd、timestamp。继续往下滑,加载更多数据,找出规律。

  

  经过观察可以发现,唯一改变的参数是offset和timestamp。第一次请求的offset值是0,第二次是20,第三次是40,key推断这个offset就是offset,count是每次请求的数据量,timestamp是时间戳。这样我们就可以通过offset参数来控制分页,通过模拟ajax请求获取数据,最后解析数据并下载。

  二、爬

  刚才分析了整个Ajax请求,接下来就是用代码来实现这个过程了。

  # _*_ coding=utf-8 _*_

import requests

import time

import os

from hashlib import md5

from urllib.parse import urlencode

from multiprocessing.pool import Pool

def get_data(offset):

"""

构造URL,发送请求

:param offset:

:return:

"""

timestamp = int(time.time())

params = {

\'aid\': \'24\',

\'app_name\': \'web_search\',

\'offset\': offset,

\'format\': \'json\',

\'autoload\': \'true\',

\'count\': \'20\',

\'en_qc\': \'1\',

\'cur_tab\': \'1\',

\'from\': \'search_tab\',

\'pd\': \'synthesis\',

\'timestamp\': timestamp

}

base_url = \'https://www.toutiao.com/api/search/content/?keyword=%E8%A1%97%E6%8B%8D\'

url = base_url + urlencode(params)

try:

res = requests.get(url)

if res.status_code == 200:

return res.json()

except requests.ConnectionError:

return \'555...\'

def get_img(data):

"""

提取每一张图片连接,与标题一并返回,构造*敏*感*词*

:param data:

:return:

"""

if data.get(\'data\'):

page_data = data.get(\'data\')

for item in page_data:

# cell_type字段不存在的这类文章不爬取,它没有title,和image_list字段,会出错

if item.get(\'cell_type\') is not None:

continue

title = item.get(\'title\').replace(\' |\', \' \') # 去掉某些可能导致文件名错误而不能创建文件的特殊符号,根据具体情况而定

imgs = item.get(\'image_list\')

for img in imgs:

yield {

\'title\': title,

\'img\': img.get(\'url\')

}

def save(item):

"""

根据title创建文件夹,将图片以二进制形式写入,

图片名称使用其内容的md5值,可以去除重复的图片

:param item:

:return:

"""

img_path = \'img\' + \'/\' + item.get(\'title\')

if not os.path.exists(img_path):

os.makedirs(img_path)

try:

res = requests.get(item.get(\'img\'))

if res.status_code == 200:

file_path = img_path + \'/\' + \'{name}.{suffix}\'.format(

name=md5(res.content).hexdigest(),

suffix=\'jpg\')

if not os.path.exists(file_path):

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

f.write(res.content)

print(\'Successful\')

else:

print(\'Already Download\')

except requests.ConnectionError:

print(\'Failed to save images\')

def main(offset):

data = get_data(offset)

for item in get_img(data):

print(item)

save(item)

START = 0

END = 10

if __name__ == "__main__":

pool = Pool()

offsets = ([n * 20 for n in range(START, END + 1)])

pool.map(main, offsets)

pool.close()

pool.join()

  这里定义了起始页START和结束页END,可以自定义设置。然后使用多进程进程池调用map()方法实现多进程下载。运行后,发现图片被保存了。

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线