工作流程
1 首先需要在一个爬虫中,获取到图片的url并存储起来。也是就是我们项目中test_spider.py中testSpider类的功能
2 项目从爬虫返回,进入到项目通道也就是pipelines中
3 在通道中,在第一步中获取到的图片url将被scrapy的调度器和下载器安排下载。
4 下载完成后,将返回一组列表,包括下载路径,源抓取地址和图片的校验码
大致的过程就以上4步,那么我们来看下代码如何具体实现
1 创建项目
scrapy startproject cnbeta
2 创建模板
进入项目目录中
scrapy genspider -t crawl cnb cnbeta.com / cnb为模板名称
3 修改配置文件
ROBOTSTXT_OBEY = False 不遵守协议
USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1' 重定向
ITEM_PIPELINES = {
'cnbeta.pipelines.CnbetaPipeline': 300,
} 开启管道
IMAGES_URLS_FILED = "image_urls" # 对应item里面设定的字段 取到图片的url
IMAGES_STORE = "E:\\cnbeta\\images" # 图片下载路径
IMAGES_EXPIRES = 90 #项目图片保存时间
IMAGES_MIN_HEIGHT = 100 # 图片大小
IMAGES_MIN_WIDTH = 100 # 图片大小
3.根目录添加启动文件
新建一个app为启动文件
from scrapy import cmdline
通过cmd启动项目方法1
cmdline.execute(['scrapy','crawl','cnb'])
#方式二
cmdline.execute('scrapy crawl cnb'.split())
4 爬取数据
-- coding: utf-8 --
import scrapy
from lxml import etree
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from w3lib import html
from cnbeta.items import CnbetaItem
class CnbSpider(CrawlSpider):
name = ‘cnb’
allowed_domains = [‘cnbeta.com’]
start_urls = [‘http://cnbeta.com/’]
rules = (
# allow 是范围 calllack对应下面的一些方法 follow进一步可以调取他里面的页面
Rule(LinkExtractor(allow=r'articles/.*'), callback='parse_item', follow=True),
)
def parse_item(self, response):
# 标题
title = response.xpath('//div[@class="cnbeta-article"]/header/h1/text()').get()
# 发布时间
pub_time = response.xpath('//div[@class="cnbeta-article"]/header/div[@class="meta"]/span[1]/text()').get()
# 来源
origin_orginal = response.xpath(
'//div[@class="cnbeta-article"]/header/div[@class="meta"]/span[@class="source"]').get()
# 过滤a和span标签获得来源
origin = html.remove_tags(origin_orginal, which_ones=('a', 'span')).strip() #去除空白字符
# 内容
# 1.源码
content_orginal = response.xpath('//div[@class="cnbeta-article-body"]/div[@class="article-content"]').get()
# 2.过滤标签
content_parse = html.remove_tags(content_orginal, keep=('img',)).strip() # 除了img之外的网页标签全部都删除 只保留文本和保留的标签
# content_parse = html.remove_tags(content_orginal, which_ones=('img',)) #跟上面相反 只删除这个指定的标签
# 页面转换
content_html = etree.HTML(content_parse)
# 内容里的图片url地址列表
image_urls = content_html.xpath('//img/@src')
# print('title',title)
# print(pub_time)
# print(origin[3:])
# print(content_parse)
# print(image_urls)
# 模型类传递
item =CnbetaItem()
# 进行赋值
item['title'] = title
item['pub_time'] = pub_time
item['origin'] = origin
item['content_parse'] = content_parse
item['image_urls'] = image_urls
return item
5 item结构体
import scrapy
class CnbetaItem(scrapy.Item):
title = scrapy.Field()
pub_time = scrapy.Field()
origin = scrapy.Field()
content_parse = scrapy.Field()
image_urls = scrapy.Field()
6管道
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline # 图片下载所需要的地址
class CnbetaPipeline(ImagesPipeline):
# 设置默认的header
default_headers = {
'referer': 'http://www.cnbeta.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'
}
# 通过配置文件获取的image地址
def get_media_requests(self, item, info):
for image_url in item['image_urls']:
self.default_headers['referer'] = image_url
yield Request(image_url, headers=self.default_headers)
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok] # 为了遍历出图片的url
if not image_paths:
raise DropItem("Item contains no images")
item['image_paths'] = image_paths # 吧遍历出的图片url集传值到item
return item
#def item_completed(self, results, item, info): 这种就是不重写也能使用
# if isinstance(item, dict) or self.images_result_field in item.fields:
# item[self.images_result_field] = [x for ok, x in results if ok]
# return item
get_meida)_requests是从管道中取出图片的url并调用request函数去获取这个url
当下载完了图片后,将图片的路径以及网址,校验码保存在item中
接下来的图片都会下载到这里,如果想修改full目录,
from scrapy.pipelines.images import ImagesPipeline,进入ImagesPipeline源码查询full进行修改
不过这还不够,进入源码后
from scrapy.pipelines.files import FileException, FilesPipeline 在进入这个FilesPipeline的源码查full进行修改成自己想要的目录,不过一般都使用默认的不建议修改