Link Extractors 中文文档:https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/link-extractors.html
Link Extractors 英文文档:http://doc.scrapy.org/en/latest/topics/link-extractors.html
利用爬虫Scrapy中的LinkExtractor(链接提取器)爬租房信息(全站爬虫):https://www.jianshu.com/p/57c1e34c03cb
scrapy高级用法之自动分页:https://my.oschina.net/u/2351685/blog/612940?fromerr=QnjXr0Pi
python爬虫之Scrapy框架( CrawlSpider ):https://www.cnblogs.com/sui776265233/p/9724147.html
CrawlSpider使用分析(详解):https://blog.csdn.net/godot06/article/details/81672900
链接提取器
链接提取器 的 目的 就是从 网页(scrapy.http.Response 对象
) 中,将最终 跟随(follow) 网页(即 scrapy.http.Response 对象
) 的 链接 提取出来。简单的说:就是用于从服务器返回的 response 里抽取 url,用以进行之后的操作。
可以在 Scrapy 中 直接使用 scrapy.linkextractors import LinkExtractor
提取链接,你也可以创建自己的自定义链接提取器,以满足您的需求通过实现一个简单的界面。
每个 link extractor(链接提取器)有唯一的公共方法是 extract_links,
它 接收一个Response对象 并返回一个 scrapy.link.Link
对象 列表。链接提取器要被实例化一次,但是它的 extract_links
方法可以被 不同 的 网页(即 scrapy.http.Response 对象
)调用好几次,用来 提取 不同 网页中 跟随 的 链接。
Link Extractors在 CrawlSpider
类( 在 Scrapy 可用 )中使用,通过一套规则,但你也可以用它在你的Spider中,即使你不是从 CrawlSpider
继承的子类,因为它的目的很简单:提取链接。
内置链接提取器参考
Scrapy 提供的 Link Extractor 类在 scrapy.linkextractors
模 块提供。 默认的 link extractor 是 LinkExtractor
, 其实就是 LxmlLinkExtractor
:
from scrapy.linkextractors import LinkExtractor
以前的 Scrapy 版本中曾经有过其他链接提取器类,但 现在已经过时了。
LxmlLinkExtractor
class scrapy.linkextractors.lxmlhtml.
LxmlLinkExtractor
(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True)
LxmlLinkExtractor 是推荐的 链接提取器 与 方便的 过滤选项。它使用 lxml 的强大的 HTMLParser 实现。
参数 解释:
- allow( 正则表达式 或 正则表达式列表 ): 一个单一的正则表达式(或正则表达式列表),(绝对)urls 必须匹配才能提取。如果没有给出(或为空),它将匹配所有链接。
- deny( 正则表达式 或 正则表达式列表 ): 一个正则表达式(或正则表达式列表),(绝对)urls必须匹配才能排除(即不提取)。它优先于 allow 参数。如果没有给出(或为空),它不会排除任何链接。,可以 和 allow 配合一起用,前后夹击,参数和 allow 一样。
- allow_domains( str 或 str 的 list ):允许 的 域名 或者 域名列表。即 会被提取的链接的 domains。其实这个和 spider 类里的 allowdomains 是一个作用,即 抓取哪个域名下的网站。
- deny_domains(str 或 str 的 list ):拒绝 的 域名 或者 域名列表。即 不会被提取链接的 domains。和 allowdomains 相反,即 拒绝哪个域名下的网站。
- deny_extensions( list ):包含在提取链接时应该忽略的扩展的单个值或字符串列表。即不允许的扩展名。如果没有给出(默认 是 None),它将默认为 IGNORED_EXTENSIONS 在 scrapy.linkextractors 包中定义的 列表 。(参考: http://www.xuebuyuan.com/296698.html)
- restrict_xpaths( str 或 list ):一个XPath(或XPath的列表),它定义了从Response哪些区域中来提取链接。即 在网页哪个区域里提取链接,可以用 xpath 表达式和 css 表达式这个功能是划定提取链接的位置,让提取更加精准。如果给出,只有那些XPath选择的文本将被扫描链接。参见下面的例子。即 使用 xpath表达式,和allow共同作用过滤链接。
- restrict_css( str 或 list ):一个CSS选择器(或选择器列表),用于定义响应中应提取链接的区域。同 restrict_xpaths。
- tags( str 或 list ):提取链接时要考虑的 标签或标签列表。默认为('a', 'area')。即 默认提取a标签和area标签中的链接
- attrs( list ):在查找要提取的链接时应该考虑的属性或属性列表(仅适用于参数中指定的那些标签tags )。默认为('href',)。即 默认提取 tags 里的 href 属性,也就是 url 链接。
- canonicalize( boolean ):规范化每个提取的url(使用 w3lib.url.canonicalize_url)。默认为True。 canonicalize each extracted url (using w3lib.url.canonicalize_url). Defaults to
False
. Note that canonicalize_url is meant for duplicate checking; it can change the URL visible at server side, so the response can be different for requests with canonicalized and raw URLs. If you’re using LinkExtractor to follow links it is more robust to keep the defaultcanonicalize=False
. - unique( boolean ):是否对提取的链接进行过滤。即 这个地址是否要唯一,默认true,重复收集相同的地址没有意义。
- process_value ( callable ) – 它接收来自扫描标签和属性提取每个值,可以修改该值,并返回一个新的,或返回 None 完全忽略链接的功能。如果没有给出,process_value 默认是 lambda x: x。其实就是:接受一个函数,可以立即对提取到的地址做加工,这个作用比较强大。比如,提取用 js 写的链接:
例如,从这段代码中提取链接: <a href="javascript:goToPage('../other/page.html'); return false">Link text</a>你可以使用下面的这个
process_value
函数:def process_value(value):m = re.search("javascript:goToPage\('(.*?)'", value)if m:return m.group(1)
- strip :把 提取 的 地址 前后多余的空格删除,很有必要。whether to strip whitespaces from extracted attributes. According to HTML5 standard, leading and trailing whitespaces must be stripped from
href
attributes of<a>
,<area>
and many other elements,src
attribute of<img>
,<iframe>
elements, etc., so LinkExtractor strips space chars by default. Setstrip=False
to turn it off (e.g. if you’re extracting urls from elements or attributes which allow leading/trailing whitespaces).
Spider
在 spider 中使用 LinkExtractor (连接提取器)
示例代码:
# -*- coding: utf-8 -*-import scrapy
from scrapy.linkextractors import LinkExtractorclass DouBan(scrapy.Spider):name = 'douban_spider'allowed_domains = ['book.douban.com']start_urls = ['https://book.douban.com/top250']# 自定义配置。自定义配置会覆盖 setting.py 中配置,即 优先级 大于 setting.py 中配置custom_settings = {'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ''AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',}def parse(self, response):link_extractor = LinkExtractor(allow=(r'subject/\d+/$',), )links = link_extractor.extract_links(response)print(links)for link in links:# print(link.url, link.text)print(link.url)if __name__ == '__main__':from scrapy import cmdlinecmdline.execute('scrapy crawl douban_spider'.split(' '))
CrawlSpider
CrawlSpider 官网文档(英文):http://doc.scrapy.org/en/latest/topics/spiders.html#crawlspider
CrawlSpider 官网文档(中文):https://scrapy-chs.readthedocs.io/zh_CN/latest/topics/spiders.html#crawlspider
CrawlSpider 除了从 Spider类 继承过来的属性外,还提供了一个新的属性 rules 来提供跟进链接(link)的方便机制,这个机制更适合从爬取的网页中获取 link 并继续爬取的工作。
rules 包含一个或多个 Rule 对象的集合。每个 Rule 对爬取网站的动作定义了特定规则。如果多个 Rule 匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。
所以:规则的顺序可以决定获取的数据,应该把 精确匹配的规则放在前面,越模糊的规则放在后面。
CrawlSpider 也提供了一个可复写的方法:parse_start_url(response)
当 start_url 的请求返回时,该方法被调用。该方法分析最初的返回值并必须返回一个 Item 对象或一个 Request 对象或者一个可迭代的包含二者的对象
注意:当编写 CrawlSpider 爬虫 的 规则 时,不要使用 parse 作为回调函数。 由于 CrawlSpider 使用 parse 方法来实现其逻辑,如果覆盖了 parse 方法,CrawlSpider 将会运行失败。
Rule 和 Link Extractors 多用于全站的爬取
Rule
爬取规则(Crawling rules)(英文):http://doc.scrapy.org/en/latest/topics/spiders.html#crawling-rules
爬取规则(Crawling rules)(中文):https://scrapy-chs.readthedocs.io/zh_CN/latest/topics/spiders.html#crawling-rules
更多 Scrapy rules 使用示例:点击打开链接
Rule 是在定义抽取链接的规则:
class scrapy.contrib.spiders.Rule(link_extractor,callback=None,cb_kwargs=None,follow=None,process_links=None,process_request=None)
参数解释:
- link_extractor:是一个 Link Extractor 对象。其定义了如何从爬取到的 页面(即 response) 提取链接的方式。
- callback:是一个 callable 或 string(该Spider中同名的函数将会被调用)。从 link_extractor 中每获取到链接时将会调用该函数。该回调函数接收一个 response 作为其第一个参数,并返回一个包含 Item 以及 Request 对象(或者这两者的子类)的列表。
- cb_kwargs:包含传递给回调函数的参数(keyword argument)的字典。
- follow:是一个 boolean 值,指定了根据该规则从 response 提取的链接 是否 需要跟进。如果 callback 为 None,follow 默认设置 True,否则默认 False。当 follow 为 True 时:爬虫会从获取的 response 中 取出符合规则的 url,再次进行爬取,如果这次爬取的 response 中还存在符合规则的 url,则再次爬取,无限循环,直到不存在符合规则的 url。 当 follow 为 False 时:爬虫只从 start_urls 的 response 中取出符合规则的 url,并请求。
- process_links:是一个callable或string(该Spider中同名的函数将会被调用)。从link_extrator中获取到链接列表时将会调用该函数。该方法主要是用来过滤。
- process_request:是一个callable或string(该spider中同名的函数都将会被调用)。该规则提取到的每个request时都会调用该函数。该函数必须返回一个request或者None。用来过滤request。
豆瓣图书 top250 示例爬虫代码
用豆瓣图书 top250 写一个小例子。豆瓣图书 Top 250:https://book.douban.com/top250
也可以使用 scrapy genspider -t crawl douban douban.com 快速创建 CrawlSpider 模板 的代码:
from scrapy.spiders import CrawlSpider, Rule 等价于 from scrapy.spiders.crawl import CrawlSpider, Rule
可以查看 scrapy/spiders/__init__.py ,最终导入的还是 from scrapy.spiders.crawl import CrawlSpider, Rule
创建工程:
用 Pycharm 打开工程,可以看到生成一个 模板 爬虫:
改写模板爬虫:
# -*- coding: utf-8 -*-from scrapy.spiders.crawl import Rule, CrawlSpider
from scrapy.linkextractors import LinkExtractorclass DouBan(CrawlSpider):name = 'douban_spider'allowed_domains = ['book.douban.com']start_urls = ['https://book.douban.com/top250']# 自定义配置。自定义配置会覆盖 setting.py 中配置,即 优先级 大于 setting.py 中配置custom_settings = {'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ''AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'}rules = (Rule(LinkExtractor(allow=('subject/\d+/$',)), callback='parse_items'),)def parse_items(self, response):print('{0} step into : parse_items(self, response)'.format(self.name))print('current url : {0}'.format(response.url))passif __name__ == '__main__':from scrapy import cmdlinecmdline.execute('scrapy crawl douban_spider'.split(' '))
运行爬虫:
- 1. 可以直接运行 example.py 这个文件。
- 2. 也可以在项目目录命令行运行命令:scrapy crawl douban_spider
可见爬取了很多 url,这些 url 是怎么获得的呢 ? 其实就是 Link Extractors 提取出来的。 在 rule 中定义了 LinkExtractors,LinkExtractors 接收的一个参数是 allow=(‘subject/\d+/$’,) ,是一个正则表达式。
爬虫运行流程
- 1.scrapy 请求 start_urls , 获取到 response
- 2.使用 LinkExtractors 中 allow 的内容去匹配 response,获取到 url
- 3.请求这个 url , 然后服务器返回的 response 交给 callback 指向的方法处理
以上是 follow 没有设置(默认为 False 的情况),在爬取到 25 个 url 的时候程序终止了。
如果将follow设置为True,将程序 中 Rule 添 一个 follow=True 参数即可。如下:
rules = (Rule(LinkExtractor(allow=('subject/\d+/$',)),callback='parse_items',follow=True),)
再次运行爬虫,发现爬虫(不被反爬的话)会跑很久不停下。因为在页面中有很多匹配 Rule 中正则的 URL。他们的 url 也符合规则,就会被不断的爬下来。
配置 logging 并 把 log 保存到文件中
可以在控制台中可以看到有很多的 log 输出。如果我们想把 log 保存到文件。可以在 setting.py 配置。
Scrapy 提供 5层 logging 级别:
- CRITICAL:严重错误(critical)
- ERROR:一般错误(regular errors)
- WARNING:警告信息(warning messages)
- INFO:一般信息(informational messages)
- DEBUG: 调试信息(debugging messages)
通过在 setting.py 中进行以下设置可以被用来配置 logging:
- LOG_ENABLED 默认: True,启用logging
- LOG_ENCODING 默认: utf-8,logging使用的编码
- LOG_FILE 默认: None,在当前目录里创建logging输出文件的文件名
- LOG_LEVEL 默认: DEBUG,log的最低级别
- LOG_STDOUT 默认: False,如果为 True,进程所有的标准输出(及错误)将会被重定向到log中。例如,执行 print “hello” ,其将会在Scrapy log中显示。
在 settings.py 配置 logging
LOG_FILE = 'douban_spider.log'
LOG_LEVEL = 'DEBUG'
就可以将 log 输出到 douban_spider.log 文件中。
爬虫运行结果截图:
示例腾讯招聘所有页面的职位信息
http://www.cnblogs.com/xinyangsdut/p/7628770.html
Item 代码:
# -*- coding: utf-8 -*-import scrapyclass TencentItem(scrapy.Item):# define the fields for your item here like:# 职位名name = scrapy.Field()# 详细链接detailLink = scrapy.Field()# 职位信息positionInfo = scrapy.Field()# 人数peopleNumber = scrapy.Field()# 工作地点workLocation = scrapy.Field()# 发布时间publishTime = scrapy.Field()
spider 代码:
# -*- coding: utf-8 -*-
import scrapy
from douban.items import TencentItem
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Ruleclass TencentSpider(CrawlSpider):name = 'tencent'allowed_domains = ['tencent.com']start_urls = ['http://hr.tencent.com/position.php?&start=0#a']rules = (Rule(LinkExtractor(allow=r'position\.php\?&start=\d+'), callback='parse_item', follow=True),)def parse_item(self, response):# i = {}# i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()# i['name'] = response.xpath('//div[@id="name"]').extract()# i['description'] = response.xpath('//div[@id="description"]').extract()# return ifor each in response.xpath('//*[@class="even"]'):name = each.xpath('./td[1]/a/text()').extract()[0]detailLink = each.xpath('./td[1]/a/@href').extract()[0]positionInfo = each.xpath('./td[2]/text()').extract()[0]peopleNumber = each.xpath('./td[3]/text()').extract()[0]workLocation = each.xpath('./td[4]/text()').extract()[0]publishTime = each.xpath('./td[5]/text()').extract()[0]# print name, detailLink, catalog,recruitNumber,workLocation,publishTimeitem = TencentItem()item['name'] = nameitem['detailLink'] = detailLinkitem['positionInfo'] = positionInfoitem['peopleNumber'] = peopleNumberitem['workLocation'] = workLocationitem['publishTime'] = publishTimeyield itemif __name__ == '__main__':from scrapy import cmdlinecmdline.execute('scrapy crawl tencent'.split(' '))
pipeline 代码:
# -*- coding: utf-8 -*-import jsonclass TencentPipeline(object):def __init__(self):self.filename = open("tencent.json", "w")def process_item(self, item, spider):text = json.dumps(dict(item), ensure_ascii=False) + ",\n"self.filename.write(text)return itemdef close_spider(self, spider):self.filename.close()
setting.py 里面启用 pipeline 配置:
ITEM_PIPELINES = {'tencent.pipelines.TencentPipeline': 300,
}
运行爬虫,运行结果截图:
使用 CrawlSpider 爬取 校花网 图片
校花网:http://www.521609.com/
Item Pipeline 和 Spider----- 基于 scrapy 取校花网的信息 编写 item pipeline:
https://cloud.tencent.com/developer/article/1098246
上面 这个地址 是 使用 spider 爬取校花网图片,现在改用 CrawlSpider 同时有去重的功能,可以爬取多页乃至全部页面。
上面 的 下载图片是在 pipeline 中 通过 Request 请求一个 图片的URL来实现的,现在改成 通过 scrayp 自带的 图片中间件 ImagesPipeline (https://docs.scrapy.org/en/latest/topics/media-pipeline.html?highlight=pipeline)来实现图片的下载。
更多关于 ImagesPipeline
scrapy 的常用 ImagesPipeline 重写实现:https://www.jianshu.com/p/cd05763d49e8
使用 Scrapy 自带的 ImagesPipeline下载图片,并对其进行分类:https://www.cnblogs.com/Kctrina/p/9523553.html
使用 FilesPipeline 和 ImagesPipeline:https://www.jianshu.com/p/a412c0277f8a
item.py :
class MMItem(scrapy.Item):image_urls = scrapy.Field()images = scrapy.Field()img_name = scrapy.Field()image_paths = scrapy.Field()pass
pipelines.py:
# -*- coding: utf-8 -*-import os
from . import settings
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItemclass MMPipeline(ImagesPipeline):# def get_media_requests(self, item, info):## # 这个方法是在发送下载请求之前调用的,其实这个方法本身就是去发送下载请求的# for image_url in item['image_urls']:# yield scrapy.Request(image_url)def get_media_requests(self, item, info):# 这个方法是在发送下载请求之前调用的,其实这个方法本身就是去发送下载请求的request_objs = super(MMPipeline, self).get_media_requests(item, info)for request_obj in request_objs:# 向 request 对象 的 示例 动态 添加 属性request_obj.item = itemreturn request_objsdef item_completed(self, results, item, info):# 重写父类 方法"""所有图片处理完毕后(不管下载成功或失败),会调用item_completed进行处理results 是一个 list 第一个为图片下载状态,get_media_requests 在图片下载完毕后,处理结果会以二元组的方式返回给 item_completed()函数的results,图片下载状态定义如下:(success, image_info_or_failure)success 表示图片是否下载成功;image_info_or_failure 是一个字典"""# super(MMPipeline, self).item_completed(results, item, info)image_paths = [x['path'] for ok, x in results if ok]if not image_paths:raise DropItem("Item contains no images")item['image_paths'] = image_pathsreturn itemdef file_path(self, request, response=None, info=None):# 这个方法是在图片将要被存储的时候调用,来获取这个图片存储的路径raw_path = super(MMPipeline, self).file_path(request, response, info)# 'http://www.521609.com/uploads/allimg/110918/12310035925-5.jpg'current_url = request.url# ['http://www.521609.com/uploads/', '/110918/12310035925-5.jpg']temp = current_url.split('allimg')# '大庆体校张可(5)'img_name_prefix = request.item.get('img_name')img_name_suffix = temp[1].split('/')[-1]category = temp[1].split('/')[-2]image_name = img_name_prefix + img_name_suffiximage_path = os.path.join(category, image_name)return image_path
mmspider.py:
# -*- coding: utf-8 -*-from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from douban.items import MMItemclass MMSpider(CrawlSpider):name = 'xiaohua'allowed_domains = ['www.521609.com']start_urls = ['http://www.521609.com']# start_urls = ['http://www.521609.com/xiaoyuanmeinv/10464_5.html']# 自定义配置。自定义配置会覆盖 setting.py 中配置,即 优先级 大于 setting.py 中配置custom_settings = {'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ''AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',# 'LOG_FILE': 'MMSpider.log',# 'LOG_LEVEL': 'DEBUG''LOG_ENABLED': False, # 关闭 scrapy 中的 debug 打印'LOG_LEVEL': 'INFO'}rules = (# 匹配 xiaohua/ 和 meinv/ 所有 URLRule(LinkExtractor(allow=('xiaohua/\d+_?\d+', r'meinv/\d+_?\d+')), callback='parse_img', follow=True),Rule(LinkExtractor(allow=('xiaohua/', 'meinv/')), follow=True))def parse_img(self, response):xiaohua_name = response.xpath('//div[@class="title"]/h2/text()').extract_first()link_extractor = LinkExtractor(allow='uploads/allimg', # 匹配的 URLdeny='(lp\.jpg)$', # 排除的 URL。这里排除掉 以 lp.jpg 结尾 的 缩略图 URLtags=('img', ), # 要提取链接的 标签attrs=('src', ), # 提取的连接restrict_xpaths='//div[@class="picbox"]', # 在 xpath 指定区域 匹配deny_extensions='' # 禁用扩展。默认会把 .jpg 扩展名的URL后缀过滤掉,这里禁用。)all_links = link_extractor.extract_links(response)img_item = MMItem()for link in all_links:print('\t{0} : {1}'.format(xiaohua_name, link.url))# 这里必须把 URL 放到 一个 list 里面,# 通过查看源码可以知道 image_urls 字段 必须是一个 url 的 listimg_item['image_urls'] = [link.url, ]img_item['img_name'] = xiaohua_nameyield img_itemif __name__ == '__main__':from scrapy import cmdlinecmdline.execute('scrapy crawl xiaohua'.split(' '))
setting.py:
ROBOTSTXT_OBEY = False # 禁用 robots.txt ITEM_PIPELINES = {'xiaohua.pipelines.MMPipeline':5,
}IMAGES_STORE = 'img_dir' # 设置图片下载路径目录
运行结果截图:
示例代码 2:
# -*- coding: utf-8 -*-import os
import requests
from pathlib import Path
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractorclass MMSpider(CrawlSpider):name = 'mm_spider'allowed_domains = ['www.521609.com']start_urls = ['http://www.521609.com']# start_urls = ['http://www.521609.com/xiaoyuanmeinv/10464_5.html']# 自定义配置。自定义配置会覆盖 setting.py 中配置,即 优先级 大于 setting.py 中配置custom_settings = {'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ''AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',# 'LOG_FILE': 'MMSpider.log',# 'LOG_LEVEL': 'DEBUG''LOG_ENABLED': False, # 关闭 scrapy 中的 debug 打印'LOG_LEVEL': 'INFO'}rules = (# 匹配 包含 xiaohua/ 和 meinv/ 所有 URLRule(LinkExtractor(allow=(r'xiaohua/\d+_?\d+', r'meinv/\d+_?\d+')), callback='parse_img', follow=True),Rule(LinkExtractor(allow=(r'xiaohua/', 'meinv/')), follow=True))# def parse(self, response):# print(response.url)# super(MMSpider, self).parse(response)# passdef parse_img(self, response):spider_name = self.namecurrent_url = response.urlprint(f'current_url:{current_url}')mm_name = response.xpath('//div[@class="title"]/h2/text()').extract_first()link_extractor = LinkExtractor(allow='uploads/allimg', # 匹配的 URLdeny=r'(lp\.jpg)$', # 排除的 URL。这里排除掉 以 lp.jpg 结尾 的 缩略图 URLtags=('img',), # 要提取链接的 标签attrs=('src',), # 提取的连接restrict_xpaths='//div[@class="picbox"]', # 在 xpath 指定区域 匹配deny_extensions='' # 禁用扩展。默认会把 .jpg 扩展名的URL后缀过滤掉,这里禁用。)all_links = link_extractor.extract_links(response)# 可以使用自定义的 item,也可以直接使用 Python 的 dict,# 因为 item 本身就是一个 python类型的 dict# img_item = MMItem()img_item = dict()image_urls_list = list()for link in all_links:print(f'\t{mm_name}:{link.url}')image_urls_list.append(link.url)else:img_item['img_name'] = mm_nameimg_item['image_urls'] = image_urls_list# yield img_itemprint(f'\t{img_item}')for img_url in image_urls_list:file_name = img_url.split('/')[-1].split('.')[0]dir_path = f'./{mm_name}'if not Path(dir_path).is_dir():os.mkdir(dir_path)file_path = f'./{mm_name}/{file_name}.jpg'r = requests.get(url=img_url)if 200 == r.status_code:with open(file_path, 'wb') as f:f.write(r.content)else:print(f'status_code:{r.status_code}')passif __name__ == '__main__':from scrapy import cmdlinecmdline.execute('scrapy crawl mm_spider'.split())pass