2020-07-19--scrapy框架2

2020-07-20  本文已影响0人  program_white

scrapy调试

通常,运行scrapy爬虫的方式是在命令行输入scrapy crawl ,调试的常用方式是在命令行输入scrapy shell 。总的来说,调试方法比较单一。
其实,还有两种调试方法,可以在pycharm中实现调试。

1.使用scrapy.cmdline的execute方法 首先,在项目文件scrapy.cfg的同级建立main.py文件(注意,必须是同级建立),在其中键入如下代码:

from scrapy.cmdline import execute

execute('scrapy crawl blog'.split())
# 或
# execute(['scrapy', 'crawl', 'spider_name'])   spider_name替换为你自己的爬虫名称

Spiders

Spider类定义了如何爬取某个网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。简而言之,Spider就是你定义爬取的动作及分析某个网页(或者是有些网页)的地方。

对spider来说,爬取的循环类似如下:

以初始的URL初始化Request,并设置回调函数。当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。spider中初始的request是通过调用start_requests() 来获取。start_requests() 读取start_urls中的URL,并以parse为回调函数生成 Request。

在回调函数内分析返回的(网页)内容,返回 Item 对象、dict、 Request 或者一个包括三者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。

在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。

最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)

Scrapy爬取博客园精华区内容

之前我们都是爬取了一个页面,这次爬取多个页面

编写items.py文件 定义需要爬取的内容。

class CnblogsItem(scrapy.Item):
    # define the fields for your item here like:
    post_author = scrapy.Field()    #发布作者
    author_link = scrapy.Field()    #作者博客主页链接
    post_date = scrapy.Field()      #发布时间
    digg_num = scrapy.Field()       #推荐数
    title = scrapy.Field()          #标题
    title_link = scrapy.Field()     #标题链接
    item_summary = scrapy.Field()   #摘要
    comment_num = scrapy.Field()    #评论数
    view_num = scrapy.Field()       #阅读数

在spiders/blog.py中编写爬虫:

    def parse(self, response:HtmlResponse):
        # BlogItem
        # 获取文章对象列表
        blist = response.xpath('//div[@id="post_list"]/div[@class="post_item"]')
        print(blist)

        for it in blist:
            blog = CnblogsItem()

            #作者
            auth = it.xpath('.//div[@class="post_item_body"]/div[1]/a/text()').extract_first()
            #作者blog主页连接
            auth_url = it.xpath('.//div[@class="post_item_body"]/div[1]/a/@href').extract_first()
            #发布时间
            time = it.xpath('.//div[@class="post_item_body"]/div[1]/text()').extract()
            # 推荐数
            digg_num = it.xpath('./div[1]/div[1]/span/text()').extract_first()
            # 标题
            title = it.xpath('.//div[@class="post_item_body"]//h3/a/text()').extract_first()
            # 标题链接
            title_link = it.xpath('.//div[@class="post_item_body"]//h3/a/@href').extract_first()
            # 摘要
            item_summary = it.xpath('.//div[@class="post_item_body"]/p/text()').extract_first()
            # 评论数
            comment_num = it.xpath('.//div[@class="post_item_body"]/div[1]/span[1]/a/text()').extract_first()
            # 阅读数
            view_num = it.xpath('.//div[@class="post_item_body"]/div[1]/span[2]/a/text()').extract_first()

            print(auth,auth_url,time,digg_num,title,title_link,item_summary,comment_num,view_num)
            blog['post_author'] = auth
            blog['author_link'] = auth_url
            blog['post_date'] = time
            blog['digg_num'] = digg_num
            blog['title'] = title
            blog['title_link'] = title_link
            blog['item_summary'] = item_summary
            blog['comment_num'] = comment_num
            blog['view_num'] = view_num
            yield blog

        #获取下一页链接
        #a[text()="Next >"]:获取文本内容为Next >的a标签
        next = response.xpath('//a[text()="Next >"]/@href').extract_first()
        # print(next)
        if next:
            next_url = f'http://www.cnblogs.com{next}'
            yield scrapy.Request(
                next_url,
                callback=self.parse
            )

分析:

  1. 首先获取第一个url,进入parse函数,传进来的response是当前页的响应。
  2. 根据xpath语法获取每个列表项的对象,返回一个列表blist。
  3. 遍历该列表,分别获取每一项的元素对象it,在it的基础上再进行解析,分别获取作者,作者链接,发布时间。推荐数,标题,标题链接,摘要,评论数,阅读数的对象,使用extract()/extract_first()转为单个对象/列表。

4.创建item数据包,将这些数据加入item数据对象中,yield发送给引擎-->管道文件。
到此第一页的数据爬取完成。
5.利用response解析到Next按钮的链接(也就是下一页的url)
6.判断该url是否存在,如果存在,yield给调度器一个scrapy下的Request()对象,该对象传递两个值,下一个url和回调函数名,进行下一次的爬取。

当管道文件下有多个类时需要判断类型item与需要获取的类型是否一致。

CrawlSpider

class scrapy.spiders.CrawlSpider 在爬取一些特殊类型的网站时,比如一些博客类网站,其网页的链接都会有一些特殊的形式

http://www.cnblogs.com/book/7357421.html
http://www.cnblogs.com/book/7356835.html

比如我们想爬取博客链接,会发现,除了最后的几个数字不同,其他的内容是相同的,因此,我们就可以通过这个类来进行自动抓取相似的链接,而无需我们自己定义。

CrawlSpider类定义了如下的属性和方法:

CrawlSpider爬取读书网

爬取网页https://www.dushu.com/book/1163_2.html


上边的2就是页数。

一、开始一个读书网项目

scrapy startproject 项目名称
cd 项目名称/项目名称/spiders
scrapy genspider -t crawl 爬虫名称 域名

scrapy startproject dushu      #创建dushu项目
cd dushu/dushu/spiders       #进入项目下的spiders目录下
scrapy genspider -t crawl ds www.dushu.com         #创建CrawlSpider爬虫文件

使用pycharm打开项目,项目结构与上一章结构一致,但是文件中内容不同。

二、链接提取规则


class DsSpider(CrawlSpider):
    name = 'ds'
    allowed_domains = ['www.dushu.com']
    start_urls = ['https://www.dushu.com/book/1163_1.html']
    rules = (
        Rule(LinkExtractor(allow=r'/book/1163_\d+.html'), callback='parse_item', follow=True),
    )

起始url为https://www.dushu.com/book/1163_1.html,当运行爬取时,会自动匹配规则中allow的正则表达式,不断地匹配第二页,第三页的url,并且回调parse_item(),实现多页爬取。

修改parse_item方法用于解析数据:

    def parse_item(self, response:HtmlResponse):
        # 获取每个书的元素,返回元素对象列表
        blist = response.xpath('//div[@class="bookslist"]/ul/li')
        # print(blist)
        for it in blist:
            book = DushuItem()
            # 从当前it元素位置出发查询下属图片
            img = it.xpath('./div/div/a/img[1]')
            # 获取书名
            title = img.xpath('./@alt').extract_first()
            # 获取书的链接
            src = img.xpath('./@data-original').extract_first()
            # 获取书的作者
            auth = it.xpath('./div/p[1]/text()').extract_first()
            # print(title,src,auth)
            book['title'] = title
            book['src'] = src
            book['auth'] = auth

            yield book

四、修改pipelines.py文件用于写入数据

class DushuPipeline:
    def open_spider(self, spider):
        self.fp = open('dushu.json', 'wb')
        self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii=False, encoding='utf-8')
        self.fp.write(b"[")
    def process_item(self, item, spider):

        # self.fp.write(str(item)+"\n")
        self.exporter.export_item(item)
        self.fp.write(b",")
        return item

    def close_spider(self, spider):
        self.fp.write(b"]")
        self.fp.close()

items.py

import scrapy

class DushuItem(scrapy.Item):

    # define the fields for your item here like:
    src = scrapy.Field()  # 发布作者
    alt = scrapy.Field()  # 作者博客主页链接
    author = scrapy.Field()  # 发布时间

记得将settings.py中的管道和用户代理和守则修改了。
运行即可。

上一篇下一篇

猜你喜欢

热点阅读