进入页面,发现图片是动态加载的。通过Ajax加载json文件。所以对request header的url进行观察,发现start参数每次加15。所以爬取过程并不难解决,关键是图片的存储
爬的过程还是会有坑的
先看items.py,这个没啥
import scrapy
class SougouphotoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
file_name = scrapy.Field()# 获取文件的名字
picture_link = scrapy.Field()
image_results = scrapy.Field()
image_paths = scrapy.Field()
# -*- coding: utf-8 -*-
import scrapy
import demjson
from ..items import SougouphotoItem
class SougouSpider(scrapy.Spider):
name = 'sougou'
allowed_domains = ['pic.sogou.com']# 不是sougou是sogou。。。我醉了
start_urls = ['https://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category=壁纸&tag=全部&start=0&len=15']
def parse(self, response):
# 此处巨坑
content = demjson.decode(response.body.decode('gbk'))
datas = content['all_items']
for data in datas:
file_name = data['title']
picture_link = data['thumbUrl']
item = SougouphotoItem()
item['file_name'] = file_name
item['picture_link'] = [picture_link] # 打死都要记住此处是列表
yield item
urls = ['https://pic.sogou.com/pics/channel/getAllRecomPicByTag.jsp?category=壁纸&tag=全部&start={}&len=15'.format(str(i)) for i in range(15,225,15)]
for url in urls:
request = scrapy.Request(url,callback=self.parse)
yield request
注意
-
首先,搜狗的英文是sogou,我被这个害惨了,发现一只只能爬出15张。。后来才缓过神。
-
在获取json数据后,对json数据进行处理,此处如果用json.loads(response.body)会出现UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xb1 in position,后来经过多种查询和尝试,发现解决办法是用demjson库,需要pip一下,然后decode()方法解析json数据,而且response.body还有decode(‘gbk’)即content = demjson.decode(response.body.decode(‘gbk’))这样才可以正确转换为python对象
-
要注意一个data里面有很多个url,thumbUrl、pic_url、orgin_url等,并不是每一个都可以请求并获取到相应,很可能会出现404.。。即报错[scrapy.pipelines.files] WARNING: File (code: 404): Error downloading file from <GET…所以最好取多个image的url,那一个行要哪个,这里偷懒了
-
要注意,item返回的图片的url一定要是列表的形式,不然会出现ValueError: Missing scheme in request url: h
下面是piplines.py
import os
import scrapy
from sougouphoto.settings import IMAGES_STORE as images_store
from scrapy.pipelines.images import ImagesPipeline
headers = {
'Referer': 'https://pic.sogou.com/pics/recommend?category=%B1%DA%D6%BD&from=category',
'User-Ageny':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
}
class SougouphotoPipeline(ImagesPipeline):
# 继承ImagesPipline并重写两个方法
def get_media_requests(self, item, info):
# image_link = item['picture_link']
for image_link in item['picture_link']:
# 正如用不用框架实现下载图片一样,对图片的url要发起请求
yield scrapy.Request(image_link,headers=headers)
def item_completed(self, results, item, info):
# 可以知道results的结构
# 提取results里面的路径并改为自己的文件存储路径
image_path = [x['path'] for ok,x in results if ok]
item['image_paths'] = image_path
try:#此处对图片进行重命名
os.rename(images_store + image_path[0], images_store + item['file_name'] + '.jpg')
except:
pass
return item
先是重写ImagePiline里面的get_media_request方法,用来对图片url发送请求并获取相应,第二个函数获取对应的results,results长这样
[(True,
{'checksum': '2b00042f7481c7b056c4b410d28f33cf',
'path': 'full/7d97e98f8af710c7e7fe703abc8f639e0ee507c4.jpg',
'url': 'http://www.example.com/images/product1.jpg'}),
(True,
{'checksum': 'b9628c4ab9b595f72f280b90c4fd093d',
'path': 'full/1ca5879492b8fd606df1964ea3c1e2f4520f076f.jpg',
'url': 'http://www.example.com/images/product2.jpg'}),
(False,
Failure(...))]
可以看到是列表里面套元祖再套字典,所以用列表推导式提取里面的path,先是判断第一个元素是否为True,是True的话就提取里面的path固有这一条列表推导式
image_path = [x['path'] for ok,x in results if ok]
关于列表推导式,最左边的那个元素就代表是这个列表里面的元素,然后这个最左边的东西是要经过一个循环得到的,这个循环又要满足某个条件才会进行循环。
在这里的话,意思就是:序列解包,取出第一个元素是True还是False并赋值给ok,如果ok是True,就取出后面的字典并提取出名为‘path’的键作为值,这个值就作为这个列表里面的元素。
后面用os.rename()方法对图片进行重命名,这里的话需要从settings里面导入一下IMAGE_STORE这位兄台。
LOG_LEVEL = 'WARNING'
ROBOTSTXT_OBEY = False
IMAGES_STORE = 'D:\\yourphoto/'# 必须要写
DEFAULT_REQUEST_HEADERS = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
'Referer': 'https://pic.sogou.com/pics/recommend?category=%B1%DA%D6%BD&from=category',
'Cookie': 'SUID=9E6888751620940A000000005C3C5D91; SUV=1547459988264723; IPLOC=CN4420; usid=9D9D1C74E609990A000000005C446306; sct=1; CXID=AFE813F02B1F31E306F131BC626E5180; ad=tUxlylllll2tvh@9lllllVeaHuDllllltUO$kyllll9lllllp6xll5@@@@@@@@@@; ld=llllllllll2tvjlQlllllVeU@4clllllKqhDcZllll9llllllklll5@@@@@@@@@@; LSTMV=260%2C204; LCLKINT=2323; JSESSIONID=aaasiP55egOwC6sRlHQJw; tip_show_home_search=20190214; SNUID=F0288185F4F07420E30A9B41F5D7C678; SNUID=5F872E2A5B5FDA8F4D4BB9A15B2B3BDC',
}
ITEM_PIPELINES = {
# 'scrapy.contrib.pipeline.images.ImagesPipeline': 1,
'sougouphoto.pipelines.SougouphotoPipeline': 300,
}
然后 scrapy crawl sougou就完事了。。
看一哈结果