Python:Scrapy(三) 进阶:额外的一些类ItemLoader与CrawlSpider,使用原理及总结
学习自:Python Scrapy 爬虫框架实例(一) - Blue·Sky - 博客园
这一节是对前两节内容的补充,涉及内容为一些额外的类与方法,来对原代码进行改进
原代码:这里并没有用前两节的代码,而是用了另一个爬虫的代码,作用是爬取千图网的图片信息。该爬虫的基本信息:
项目名:AdilCrawler
爬虫名:thousandPic
网址:www.58pic.com
开始爬取的网址:https://www.58pic.com/c/
Item类:AdilcrawlerItem
xpath表达式:
Author:/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()
Name:/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()
# -*- coding: utf-8 -*- import scrapy # 这里使用 import 或是 下面from 的方式都行,关键要看 当前项目在pycharm的打开方式,是否是作为一个项目打开的,建议使用这一种方式。 import AdilCrawler.items as items class ThousandpicSpider(scrapy.Spider): name = 'thousandPic' allowed_domains = ['www.58pic.com'] start_urls = ['https://www.58pic.com/c/'] def parse(self, response): item = items.AdilcrawlerItem() author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract() theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract() item['author'] = author item['theme'] = theme return item
补充内容
1、日志打印,写在parse方法下:
def parse(self,response): ... self.log(author) ...
2、ItemLoader类:代替extract()、xpath()方法
1)从scrapy.loader导入ItemLoader
from scrapy.loader import ItemLoader
2)优化,写在spider.py文件
用add_xpath方法,代替XPath提取语句:xpath(xxx).extract()
import scrapy from AdilCrawler.items import AdilcrawlerItem from scrapy.loader import ItemLoader class ThousandpicoptimizeSpider(scrapy.Spider): name = 'thousandPicOptimize' allowed_domains = ['www.58pic.com'] start_urls = ['http://www.58pic.com/c/'] def parse(self, response): i = ItemLoader(item = AdilcrawlerItem(),response = response ) i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()') i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()') return i.load_item()
相当于:
i = items.AdilcrawerItem() author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract() theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract() i['author'] = author i['theme'] = theme yield i
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
i = ItemLoader(item = AdilcrawlerItem(),response = response ) i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()') i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()') yield i.load_item()
3)修改pipelines.py,目的是将爬取到的内容保存到文件中;
Spider中爬取到的内容都会以参数item的形式传入pipelines.py文件中的相关方法,比如process_item,(这一点很重要,且对所有类型的爬虫都适用)
import json class AdilcrawlerPipeline(object): def __init__(self): self.filename = open('thousandPic.json','w') def process_item(self, item, spider): # ensure_ascii=False 可以解决 json 文件中 乱码的问题。 text = json.dumps(dict(item), ensure_ascii=False) + ',\n' # 这里是一个字典一个字典存储的,后面加个 ',\n' 以便分隔和换行。 self.filename.write(text) return item def close_spider(self,spider): self.filename.close()
至于json序列化保存的方法,可以参考序列化 pickle JSON - ShineLe - 博客园
4)修改settings.py
ITEM_PIPELINES = { 'AdilCrawler.pipelines.AdilcrawlerPipeline': 300, } # 加入后,相当于开启pipeline,此时在执行爬虫,会执行对应的pipelines下的类,并执行该类相关的方法,比如这里上面的保存数据功能。
5)执行;由于在pipelines.py中已经写了文件保存方法,故此处不用-o参数输出为文件
scrapy crawl thousandPicOptimize
3、CrawlSpider类:翻页抓取
1)使用crawl模板创建一个CrawlSpider PicSpi(CrawlSpider的生成,与普通Spider不同)
scrapy genspider -t crawl PicSpi www.58pic.com
2)items.py:与之前相同;
import scrapy
class PicsItem(scrapy.Item):
authod=scrapy.Field() #作者
theme=scrapy.Field() #主题
pipelines.py同2
3)Spider文件PicSpi.py
需要用到另外三个类:LinkExtractor、CrawlSpider、Rule
from scrapy.linkextractors import LinkExtractor from scrapy.spider import CrawlSpider,Rule
完整代码:
# 导入链接规则匹配类,用来提取符合规则的链接 from scrapy.linkextractors import LinkExtractor # 导入CrawlSpider类和Rule (①) from scrapy.spiders import CrawlSpider, Rule import AdilCrawler.items as items class ThousandpicpagingSpider(CrawlSpider): name = 'thousandPicPaging' allowed_domains = ['www.58pic.com'] start_urls = ['https://www.58pic.com/c/'] # Response中的链接提取规则,返回符合规则的链接匹配对象的List # 根据翻页链接地址 http://www.58pic.com/c/1-0-0-03.html 找到相应的正则表达式 # 不能使用restrict_xpath,否则正则将失效 #(②) page_link = LinkExtractor(allow='https://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com') #(③) rules = ( Rule(page_link, callback='parse_item', follow=True), # 此处的 ','不能省略 ) # 方法parse_start_url是为了解决parse_item()不能抓取第一页数据的问题 # 原因是第一页的正则表达式形式与之后若干页不同 # 该方法是CrawlSpider类下的方法,这里重写一下即可 #(④) def parse_start_url(self, response): i = items.AdilcrawerItem() author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract() theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract() i['author'] = author i['theme'] = theme yield i #(⑤) def parse_item(self, response): i = items.AdilcrawerItem() author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract() theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract() i['author'] = author i['theme'] = theme yield i
对这段代码的说明:
①:库的导入,这一部分的内容是在通过指令生成CrawlSpider的时候自动生成的
②:得到每一页的链接
page_link = LinkExtractor(allow='https://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com')
LInkExtractor构建链接时,需要参数allow与allow_domains,参数allow是各页URL的完整正则表达式,allow_domains是限定访问的范围;这样page_link便保存了访问每一页的方法。
③:根据每页链接构建访问规则
rules = ( Rule(page_link, callback='parse_item', follow=True), # 此处的 ','不能省略 )
a、用Rule方法,参数有三项:page_link、callback、follow,作用分别是:
page_link:②中构建的链接,由于是正则表达式,所以是一系列的链接
callback:对这些链接进行处理的函数,需要在之后补充在同一个类中
follow:是否根据链接自动进行下去
b、最后,必须加,逗号,以表明这是一个Tuple元组
④:访问第一页(针对第一页URL不与正则表达式相匹配的情况):parse_start_url
⑤:访问其他页(代码相同,只是方法名不同):parse_item
i = items.AdilcrawerItem() author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract() theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract() i['author'] = author i['theme'] = theme yield i
代码内容与普通情况下的要素提取相同
4)运行;运行方法倒是相同
scrapy crawl thousandPicPaging
4、综合,将2、3结合起来,同时使用ItemLoader、CrawlSpider
import scrapy from scrapy.loader import ItemLoader from scrapy.spiders import CrawlSpider,Rule import AdilCrawler.items as items class ThousandpicpagingopSpider(CrawlSpider): name='thousandPicPagingOp' allowed_domains = ['www.58pic.com'] start_urls = ['http://www.58pic.com/c/'] page_link=LinkExtractor(allow='http://www.58pic.com/c/\S-\S-\S-\S\S.html',allow_domains='www.58pic.com') rules=( Rule(page_link,callback='parse_item',follow=True), ) def parse_start_url(self,response): i=ItemLoader(item=items.AdilcrawlerItem(),response=response) i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()') i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()') yield i.load_item() def parse_item(self, response): i = ItemLoader(item = items.AdilcrawlerItem(),response = response ) i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()') i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()') yield i.load_item()
5、总结
用CrawlSpider和ItemLoader写一个可以自动翻页的爬虫的一般流程及文件配置。
1)创建项目与爬虫
scrapy startproject XXX scrapy genspider -t crawl xxxS url
2)items.py
import scrapy class xxxItem(scrapy.Item): attr1=scrapy.Field() attr2=scrapy.Field() ... attrn=scrapy.Field()
3)pipelines.py
import json class xxxPipeline(object): def __init__(self): self.filename = open('xxx.json','w') #保存文件 def process_item(self,item,spider): # ensure_ascii=False 可以解决 json 文件中 乱码的问题。 text = json.dumps(dict(item), ensure_ascii=False) self.filename.write(text) return item def close_spider(self,spider): self.filename.close()
4)settings.py
BOT_NAME = SPIDER_MODULES = NEWSPIDER_MODULE = ROBOTSTXT_OBEY = False ITEM_PIPELINES = { 'XXX.pipelines.xxxPipeline': 300, }
5)spider.py
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.loader import ItemLoader from scrapy.spiders import CrawlSpider, Rule import XXX.items as items class XXXSpider(CrawlSpider): name = 'xxxS' allowed_domains = ['url'] start_urls = ['url'] page_link = LinkExtractor(allow='url regex', allow_domains='url') rules = ( Rule(page_link, callback='parse_item', follow=True), ) #处理首页 def parse_start_url(self, response): i = ItemLoader(item = items.XXXItem(),response = response ) i.add_xpath('attr1','attr1 xpath') i.add_xpath('attr2','attr2 xpath') yield i.load_item() # 处理其他页 def parse_item(self, response): i = ItemLoader(item = items.XXXItem(),response = response ) i.add_xpath('attr1','attr1 xpath') i.add_xpath('attr2','attr2 xpath') yield i.load_item()
6)运行爬虫
scrapy crawl xxxS
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性