小白自己在学习崔庆才的《Python3网络爬虫开发实战》的过程中,在第七章有讲到Ajax爬取头条街拍的实战,但是在自己实际编写过程中发现书上给出的代码并不能正常爬取想要的图片,这是因为作者在编写这本书的时间到现在已经过去很长的一段时间了,而网站也是在不断地改进中,有些代码已经不在适用了。
接下来给出改进的爬取头条的方法,以及避雷区。
可以看到,崔庆才书上说的“image_detail”已经找不到了,取而代之的是"image_list",所以我切记这里一定要换掉。
还有个需要注意的是,Headers里面的Request URL是“https://www.toutiao.com/api/search/content/?”,但是我在编码里写的是这个URL后发现并不能正常运行(有知道的大神可以指导下为什么),所以我们的URL还是写成“https://www.toutiao.com/search_content/?”.
头条网站搜索“街拍”后多了个人机验证,所以很多同学会发现即使代码编写正常也不能爬取到想要的图片。
所以这里我们需要使用 headers 加上Cookie。
当系统运行的时候会报错for image in images里面TypeError:‘NoneType’ object is not iterable(类型错误:“NoneType”对象不是可迭代的) ,这是因为爬取的图片结果中有些 image_list 为None。所以才会出现这些错误。
我们只需要在 for 遍历前,加上 if images: 判断是否为None。这样就能解决这个问题了。
在正常爬取网站图片的时候,会出现报错,这是因为我们新建的文件夹是用的“title”命名的,有些‘title’里面会包含一些符号,这些符号编码不能识别,所以才会报错。
这里我们避免文件命名用“title”就可以解决了,我这里用的是“picture”+offset命名的方式。
其他的就不多说了,下面给出完整代码:
import requests
from urllib.parse import urlencode
import sys
import os
import time
from hashlib import md5
from multiprocessing.pool import Pool
from requests.exceptions import RequestException
def get_page(offset):
headers={
'cookie':'tt_webid=6729065317747787275; WEATHER_CITY=%E5%8C%97%E4%BA%AC; tt_webid=6729065317747787275; csrftoken=131bbd6e68a8aac9b77420bd0a31996f; s_v_web_id=1c6b50f2963ac7633d554316bc6c37da; __tasessionId=kcw7v5v8n1566792370753',
'pragma':'no-cache',
'referer':'https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D',
'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
'x-requested-with':'XMLHttpRequest'
}#这里需要加入headers,里面有cookie,解决图片验证的问题
params={
'aid': '24',
'app_name': 'web_search',
'offset': offset,#这里不需要加引号,因为需要传参数
'format': 'json',
'keyword': '街拍',
' autoload': 'true',
'count': '20',
'en_qc': '1',
'cur_tab': '1',
'from': 'search_tab',
'pd': 'synthesis',
# 'timestamp':1566785808182
}
url='http://www.toutiao.com/search_content/?'
try:
response=requests.get(url,params=params,headers=headers)
if response.status_code==200:
return response.json()
except requests.ConnectionError:
return None
def get_images(json):
if json.get('data'):
for item in json.get('data'):
if 'title' in item and 'image_list' in item and item['image_list'] != []:
#这里需要判断是否为空
title=item['title']
images=item['image_list']
for image in images:
yield{
'image': image.get('url'),
'title': title
}#返回一个字典
def save_image(offset,item):
if not os.path.exists('picture'+str(offset)):#判断当前文件夹下是否有该文件
os.mkdir('picture'+str(offset))#创建文件夹
try:
response=requests.get("http:"+item['image'])
if response.status_code==200:
file_path='{0}/{1}.{2}'.format('picture'+str(offset),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__':
for offset in range(0, 140, 20):
json = get_page(offset)
for item in get_images(json):
save_image(offset,item)