Scrapy学艺一:初次使用

2021-06-28  本文已影响0人  狂奔的胖蜗牛

1.安装卸载升级Scrapy

// 由于我的机器同时安装有Python2和Python3的pip,所以使用Python3的pip是需要输入pip3
// 安装
pip3 install Scrapy
// 卸载
pip3 uninstall Scrapy
// 升级
pip3 install --upgrade Scrapy

2.创建Scrapy项目

// projectName项目名称
scrapy startproject projectName

得到如下结构的文件夹:

projectName/
    scrapy.cfg            # 部署配置文件

    projectName/             # 项目模块文件
        __init__.py

        items.py          # 项目items文件

        middlewares.py    # 项目中间件文件

        pipelines.py      # 项目管道文件

        settings.py       # 项目设置文件

        spiders/          # 具体的爬虫文件
            __init__.py

3.第一个爬虫程序

爬虫程序需要写在spiders文件夹内,爬取的类需要继承自Spider类,并且需要指定爬取的url和如何解析数据。

import scrapy


class QuotesSpider(scrapy.Spider):
    // 爬虫的名字,一个项目中多个爬虫不能取相同名字,需要区分开
    name = "quotes"
    // 开始请求的方法,返回路径迭代器
    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)
    // 开始解析会调用该方法,方法内可以继续请求
    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log(f'Saved file {filename}')

4.运行爬虫

// 进入项目路径,输入
scrapy crawl quotes

Scrapy执行顺序:执行scrapy.Request->执行start_requests方法->获取到数据->执行parse方法。

5.可以通过设置属性的方式设置请求地址

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    // 将地址设置成属性
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)

6.使用Scrapy Shell

终端中输入:

scrapy shell http://www.baidu.com

即可打开了Scrapy Shell,我们可以在里面测试代码、测试数据返回等。


比如测试通过css获取有title节点的元素

// 返回的是Selector对象
response.css('title')

使用.getall()方法获取元素内容

// 返回的是title的文本内容
response.css('title::text').getall()

使用.get()方法获取首个节点

// 返回首个节点文本内容
response.css('title::text').get()

返回指定下标的内容

response.css('title::text')[1].get()

可以通过.re()方法,设置正则匹配规则,过滤数据,然后返回数据

response.css('title::text').re(r'Quotes.*')

可以在shell中输入view(response)来查看获取到的数据信息。


当然,也可以使用XPath来获取节点

response.xpath('//title')
response.xpath('//title/text()').get()
作用同:
response.css('title')
response.css('title::text').get()

实际上,css获取的方式,在内部会转换成xpath来获取。

7.保存数据

可以看到,在parse方法内,通过yield生成了迭代器。运行爬虫,我们能看到有抓取到的数据打印。如果要把数据保存起来,运行爬虫的时候,可以这样:

scrapy crawl quotes -O quotes.json

Scrapy会将数据写入到quotes.json文件中。这种方式对小项目可行,大型项目的话,就需要用到管道了,在项目中位置项目名/pipelines.py中。

8.继续爬取下一个网页

在parse方法中,我们解析到了下一个网页,那么,如何让Scrapy继续读取该网页呢,使用scrapy.Request()方法即可

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            // response.urljoin()方法拼接出下一个url地址
            next_page = response.urljoin(next_page)
            // 我们可以设置下一个爬取的网页,同时指定解析的方法,然后通过yield构建成迭代器。
            yield scrapy.Request(next_page, callback=self.parse)

使用scrapy.Request方法时,我们需要提供完整的url路径,如果使用response.follow()方法,则不需要我们拼接路径。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('span small::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

由于response.follow方法可传入Selector对象,可以可以改成下面这样:

for href in response.css('ul.pager a::attr(href)'):
    yield response.follow(href, callback=self.parse)

同时,由于response.follow传入selector对象时,会自动使用href属性,所以可以继续修改:

for a in response.css('ul.pager a'):
    yield response.follow(a, callback=self.parse)

如果是selector数组,则可以使用follow_all方法

anchors = response.css('ul.pager a')
yield from response.follow_all(anchors, callback=self.parse)
// 或者简写
yield from response.follow_all(css='ul.pager a', callback=self.parse)

9.附加参数

可以通过-a传递附加参数

scrapy crawl quotes -O quotes-humor.json -a tag=humor

其中该附加参数会传递给爬虫的init方法,同时会变成属性来使用。

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        url = 'http://quotes.toscrape.com/'
        // 获取附加参数tag
        tag = getattr(self, 'tag', None)
        if tag is not None:
            url = url + 'tag/' + tag
        yield scrapy.Request(url, self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

这样,如果命令运行的时候,就可以指定tag来进行爬取。

10.总结

至此,Scrapy的初次使用完毕,总结一下,用起来还是非常方便的,我们不需要去处理数据请求,Scrapy会帮我们处理好,我们只需要关心数据的数据以及存储,相当的方便。

上一篇 下一篇

猜你喜欢

热点阅读