js 爬虫抓取网页数据(今日头条为例来尝试通过分析Ajax请求来网页数据的方法 )

优采云 发布时间: 2022-04-04 16:02

  js 爬虫抓取网页数据(今日头条为例来尝试通过分析Ajax请求来网页数据的方法

)

  文章目录

  在本文中,我们以今日头条为例,尝试通过分析Ajax请求来抓取网页数据。本次要抓拍的目标是今日头条的街拍,抓拍保存。本节代码参考了python3网络爬虫实战的6.4节,但是由于网页上的一些东西已经更新,所以本文中的代码也做了相应的修改,使其可以正常采集数据。1.准备

  首先,确保已安装 requests 库。

  2.爬取分析

  在爬取之前,先分析一下爬取的逻辑。打开今日头条首页,如图

  

  在搜索框中输入街拍,结果如图

  

  点击图片切换图片分类

  

  然后打开开发者工具,查看所有网络请求。首先打开第一个网络请求,这个请求的URL是当前连接%E8%A1%97%E6%8B%8D&pd=atlas&source=search_subtab_switch&dvpf=pc&aid=4916&page_num=0,打开Preview标签查看Response Body。发现只有页面的一部分,如图。可以分析出下面的图片数据是通过Ajax加载,然后用JavaScript渲染出来的。

  

  接下来,我们可以切换到 XHR 过滤选项卡,查看是否有任何 Ajax 请求。

  果然有一个比较常规的ajax请求,看看它的结果是否收录页面中的相关数据。

  点击rawData字段展开,可以发现有一个data字段,count字段为40,表示本次请求收录40张图片,data字段收录40条记录,分别是图片的url等信息。

  

  这证实了数据确实是由 Ajax 加载的。

  我们的目的是抓取里面的图片,这里一组图片对应上一个数据域中的一条数据。如图所示

  

  因此,我们只需要提取并下载data中每条数据的img_url字段即可。创建一个文件夹来保存这些图片。

  接下来,我们可以直接用Python来模拟这个Ajax请求,然后提取相关信息。但在此之前,我们还需要分析一下 URL 的规律。

  切换回Headers选项卡,观察其请求URL和Headers信息,如图

  

  可以看出这是一个GET请求。请求的参数有keyword、pd、source、dvpf、aid、page_num、search_json、rawJSON、search_id。我们需要找出这些参数的规则,因为这样可以方便地用程序构造请求。

  接下来,滑动界面以加载更多结果。加载的时候可以发现NetWork中有很多Ajax请求,如图:

  

  这里我们观察前后几个连接的请求变化,发现只有page_num参数在变化,每次变化都是1,所以可以找到规律,这个page_num就是偏移量,然后我们可以推断即count参数是一次得到的数据条数。所以我们可以使用page_num参数来控制分页。这样就可以通过接口批量获取数据,然后解析数据,下载图片。另外我们发现keyword参数使用的不是明文,而是加密的代码,可以借助python中的unquote包解决。

  3.实战演练

  我们刚刚分析了ajax请求的逻辑,下面使用程序来实现。

  首先,实现方法 get_page() 来加载单个 Ajax 请求的结果。唯一的变化是参数page_num,所以它作为参数传递。另外需要注意的是,这里需要构造请求头,并且需要收录cooike,否则取不到Response。该信息可以在“标题”选项卡中找到:

  

  构造参数可以在payload选项卡中找到

  

  import requests

from urllib.parse import urlencode,quote,unquote

headers = {

'Host': 'so.toutiao.com',

'Referer': 'https://so.toutiao.com/search?keyword=%E8%A1%97%E6%8B%8D&pd=atlas&dvpf=pc&aid=4916&page_num=0&search_json={%22from_search_id%22:%222022040316335201021218304330C35A48%22,%22origin_keyword%22:%22%E8%A1%97%E6%8B%8D%22,%22image_keyword%22:%22%E8%A1%97%E6%8B%8D%22}',

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36',

'X-Requested-With': 'XMLHttpRequest', # Ajax请求需要手动设置这里

'Cookie': 'passport_csrf_token=92a1b4e0108fb8384f5b81554b5b5424; tt_webid=7053044990251386398; _S_DPR=1.25; _S_IPAD=0; MONITOR_WEB_ID=7053044990251386398; ttwid=1%7CoqMwjUw5WGRdjYizT8quhnfpAchk3v_E3YLa1riJgrY%7C1648972603%7Cbaea5aebf3461426baaede977fa55b0efec3033a9f0d6a3e26684ba80f607ee9; _S_WIN_WH=1536_722'

}

def get_page(page_num):

params = {

'keyword':unquote('%E8%A1%97%E6%8B%8D') ,

'pd':'atlas',

'dvpf':'pc',

'aid': '4916' ,

'page_num':page_num,

'search_json':{"from_search_id":"2022040316335201021218304330C35A48","origin_keyword":"街拍","image_keyword":"街拍"},

'rawJSON':'1',

'search_id':'2022040317334901015013503043241DAC'

}

url = 'https://so.toutiao.com/search/?'+urlencode(params,headers)

try:

response = requests.get(url,headers=headers,params=params)

if response.status_code == 200:

return response.json()

except requests.ConnectionError:

return None

  这里我们使用urlencode()方法构造请求的GET参数,然后使用requests请求链接。如果返回的状态码为 200,调用响应的 json() 方法将结果转换为 JSON 格式并返回。

  接下来实现一个解析方法:提取每条数据的img_url字段中的图片链接,并返回图片链接。这时候就可以构建*敏*感*词*了。实现代码如下:

  def get_images(json):

if json.get('rawData'):

images = json.get('rawData').get('data')

for image in images:

link = image.get('img_url')

yield {

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

'title':"街拍",

'text':image.get('text')

}

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

  import os

from hashlib import md5

def save_image(item):

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

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

try:

response = requests.get(item.get('image'))

if response.status_code == 200:

file_path = '{0}/{1}.{2}'.format(item.get('title'),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 to Save image')

  最后,只需构造一个数组,遍历,提取图片链接,下载即可:

  from multiprocessing.pool import Pool

def main(page_num):

json = get_page(page_num)

for item in get_images(json):

print(item)

save_image(item)

GROUP_START = 1

GROUP_END = 20

if __name__ == '__main__':

# pool = Pool()

# groups = ([x*20 for x in range(GROUP_START,GROUP_END+1)]) #使用这种方式启动出现bug,原因还没有找到

# pool.map(main,groups)

# pool.close()

# pool.join()

for i in range(1,10):

main(i)

  因为博主在使用线程池有bug,一直没找到原因,所以先用for循环

  结果如下:

  

  最后,给出本文的代码地址:

  参考

  [1].Python3网络爬虫开发实战.崔庆才.——6.4

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线