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建链接时,需要参数allowallow_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、总结

CrawlSpiderItemLoader写一个可以自动翻页的爬虫的一般流程及文件配置。

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

 

posted @   ShineLe  阅读(177)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示