什么是Ajax?
简单来说就是浏览网页时该页内容浏览完后, 只需要向下滑动, 自动出现新的内容, 而不需要刷新页面. 如浏览新浪微博. 爬取Ajax类型数据, 需要用程序模拟Ajax向服务器发送请求, 根据响应内容得到我们想要的数据.
本文以今日头条为例, 作者使用Google浏览器
目的: 搜索街拍,爬取图片。
首先登录今日头条搜索街拍(https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D), 切换到如下图界面:
查看详细信息, 选中?offset=0&format=json…
当向下滑动鼠标时会发现, 会多出文件, 如下图
这些就是Ajax请求, 可以发现规律, 这些请求的区别仅仅在于offset值的不同, 并且以20为倍值.
分析请求的内容, 如下图
可以发现只有 image_list 为图片的地址, 因此我们需要获取到该内容. 除此之外, 有的不拥有 image_list选项, 因此在编写代码时需要注意判断.
代码:
import requests
from urllib.parse import urlencode
import os
"""
爬去ajax网站信息
以今日头条为例
搜索街拍, 下载图片
"""
base_url = 'https://www.toutiao.com/search_content/?'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
offset_start = 1
offset_end = 2
def get_page(offset):
"""
根据偏移量获取网页
"""
global headers
# url请求参数
params = {
'offset': offset,
'format': 'json',
'keyword': '街拍',
'autoload': 'ture',
'count': '20',
'cur_tab': '1',
'from': 'search_tab'
}
# 拼接url
url = base_url + urlencode(params)
# 请求url
try:
response = requests.get(url, headers=headers)
if response.status_code == 200: # 请求成功
return response.json()
except response.ConnectionError as e:
return None
def get_image(json_text):
"""
从json类型的文字中提取出图片地址
"""
data = json_text.get('data')
# json中是否存在data数据
if data:
for item in data:
if item.get('image_list') is None: # 判断是否存在图片链接
continue
title = item.get('title')
images = item.get('image_list') # 获取该页面的所有图片url
print(title)
for image in images:
yield {
'image': 'https:' + image.get('url'),
'title': title
}
def down_save_image(items):
"""下载图片并保存"""
global headers
dirname = items.get('title')
# 如过不存在标题目录则创建
if not os.path.exists(dirname):
os.mkdir(dirname)
try:
response = requests.get(items['image'], headers=headers)
if response.status_code == 200:
# 图片以其url/最后为名
image_name_temp = str(items.get('image')).split('/')
print(items.get('image'))
imagename = image_name_temp[len(image_name_temp)-1]
# 拼接图片名称
image_path = '{dirname}/{imagename}.{suffix}'.format(dirname=dirname, imagename=imagename, suffix='jpg')
# 保存图片到本地
if not os.path.exists(image_path):
with open(image_path, 'wb') as f:
f.write(response.content)
except response.ConnectionError as e:
print('Failed to download or save image')
def main():
global offset_start
global offset_end
# 根据起始页和终止页爬取
for offset in ([x *20 for x in range(offset_start, offset_end+1)]):
json = get_page(offset)
items = get_image(json)
for item in items:
down_save_image(item)
if __name__ == '__main__':
main()