Scrapy基础入门(一)

俏咪咪的给自己放了个小长假之后,我白汉三又回来啦。这次要开始慢慢系统学习scrapy了,这个框架真的很厉害,我只是写了个很小的例子,就只花了十行代码就完成了我之前的一篇文章的工作量,而且速度超快,个人认为非常值得学习,它上手简单并且通俗易懂

欢迎关注公众号:老白和他的爬虫

1.创建一个爬虫

Anaconda+pycharm配置Scrapy ——环境搭配与一个简单的例子这两篇文章里已经讲述了如何使用anaconda以及配置anaconda+pycharm环境,没有配置的老铁可以出门右拐,去那里配置一下,anaconda是我一直推荐使用的集成环境,它不需要你再pip很多的包了,直接通过可视化的窗口就可以安装第三方包。通过anaconda自带的spyder编辑器也可以使用scrapy但是需要配合windows下的命令提示符和mac下的终端来操作,相比之下还是pycharm方便一点。

在控制台输入创建一个项目tutorial

scrapy startproject tutorial

运行成功之后你可以看到你的pycharm的项目列表下有这样的目录

tutorial/
    scrapy.cfg            # deploy configuration file

    tutorial/             # project's Python module, you'll import your code from here
        __init__.py

        items.py          # project items definition file

        middlewares.py    # project middlewares file

        pipelines.py      # project pipelines file

        settings.py       # project settings file

        spiders/          # a directory where you'll later put your spiders
            __init__.py

tutorial/spiders目录下创建一个文件,命名为quotes_spider.py,代码如下

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 = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

简单解释一下这个实例

  • scrapy.Spider表示这个继承了这个子类,我们可以使用它的一些方法
  • name:表示这个爬虫的名字,必须是独一无二的
  • start_requests:返回可重复的Requests.通过自定义输入的起始地址,重复调用parse()解析网页
  • parse():定义处理网页的方法

2.运行一个爬虫

对于上述已经创建好的爬虫,在控制台输入以下代码:

scrapy crawl quotes

到这里你要注意这个命令的格式scrapy是我们使用scrapy框架必须要声明的,前面试过startproject表示创建一个项目,crawl表示运行一个爬虫,后面会试到更多的命令,这里的quotes是我们刚在程序里声明的name属性,记住不是它的类的名称也不是文件名。

对于上面我们创建的代码,我们也可以这样简化一下

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 = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)

这段代码和上面相比,去掉了start_requests方法,只使用start_urls存放其实地址。这些初始地址将会被scrapy的默认方法start_requests()解析,你仔细看代码会惊讶的发现根本就没有调用start_urls这个变量,这是因为parse是scrapy默认的方法。没错,就是这么神奇。

3.学会使用shell

官方的文档告诉我们通过shell命令来学会如何一步一步解析文档,但其实当我们在实际写爬虫的时候,可以利用这个命令来一步一步来修改代码,因为我们需要自己编写爬取信息的具体代码,谁也不敢保证你写的爬取信息的代码一次就成功,如果每一次都通过scrapy crawl * 这样的命令来调试,就太麻烦了,所以shell也是一个很好的调试工具。

输入命令

scrapy shell "http://quotes.toscrape.com/page/1/"

在这之前你可以访问一下网站http://quotes.toscrape.com/page/1/这是scrapy提供的事例网站。运行之后你应该能看到

这里就可以在shell下操作了,使用css选择器来选择相应标签

3.1使用css选择器

获取标签

>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]

获取标签下文本

>>> response.css('title::text').extract()
['Quotes to Scrape']

获取标签和文本

>>> response.css('title').extract()
['<title>Quotes to Scrape</title>']

上述获取标签所返回的结果都是列表形式的,下面两种方式选择第一个元素,第一种方式能够避免未找到标签而报错

>>> response.css('title::text').extract_first()
'Quotes to Scrape'
>>> response.css('title::text')[0].extract()
'Quotes to Scrape'

3.2使用xpath

除开css选择器,也可以通过xpath来选择标签。这里有必要解释一下xpath,XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言,网页HTML也是一种XML。

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').extract_first()
'Quotes to Scrape'

xpath非常的强大,scrapy selector就是基于xpath选择器完成的。

3.3实例

选取实例网站http://quotes.toscrape.com,它的html代码大致如下:

<div class="quote">
    <span class="text">“The world as we have created it is a process of our
    thinking. It cannot be changed without changing our thinking.”</span>
    <span>
        by <small class="author">Albert Einstein</small>
        <a href="/author/Albert-Einstein">(about)</a>
    </span>
    <div class="tags">
        Tags:
        <a class="tag" href="/tag/change/page/1/">change</a>
        <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
        <a class="tag" href="/tag/thinking/page/1/">thinking</a>
        <a class="tag" href="/tag/world/page/1/">world</a>
    </div>
</div>

在pycharm里输入命令行代码

scrapy shell 'http://quotes.toscrape.com'

运行完成后,

>>> response.css("div.quote")

通过结果可以看到,返回了一个符合条件的列表,选择第一个作为我们想要的数据

>>> quote = response.css("div.quote")[0]

所获取的quote也就代表着实例网站中的一个节点

下面这段代码分别获取其中的正文、作者和标签

>>> title = quote.css("span.text::text").extract_first()
>>> title
'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author = quote.css("small.author::text").extract_first()
>>> author
'Albert Einstein'
>>> tags = quote.css("div.tags a.tag::text").extract()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']

通过上面这段代码可以了解如何从一个节点中抽取信息,像实例网站中有那么多的节点,只需要设置一个循环就可以全部获取了

>>> for quote in response.css("div.quote"):
...     text = quote.css("span.text::text").extract_first()
...     author = quote.css("small.author::text").extract_first()
...     tags = quote.css("div.tags a.tag::text").extract()
...     print(dict(text=text, author=author, tags=tags))
{'tags': ['change', 'deep-thoughts', 'thinking', 'world'], 'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'}
{'tags': ['abilities', 'choices'], 'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”'}
    ... a few more of these, omitted for brevity
>>>

4.在scrapy中爬取数据

在第三节里面教会你如何使用shell调试好爬虫代码,现在回到scrapy中去尝试自己的爬虫。到目前为止,除了保存整个HTML文件还没有正式的爬取数据

一个scrapy爬虫一般都是把数据保存在字典中,这里使用yield来保存数据

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):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

运行代码

scrapy crawl quotes

就可以看到结果了

5.保存你爬取的数据

爬取好的数据可以通过以下的指令来保存

scrapy crawl quotes -o quotes.json

可以看到这比我们之前的代码只多了-o quotes.json,这个运行的结果都保存在了一个名为quotes.json的json文件中。但是这个命令面临一个问题,如果你运行两次就会有问题,为了避免这个问题,可以改用以下代码

scrapy crawl quotes -o quotes.jl

命令效果完全相同,不同的是它可以多次运行,每次把新的结果接着之前的文件插入其后。

6.获取翻页链接

在之前的爬虫实战文章里,很重要的一个操作就是如何获取网站的翻页链接,在scrapy中也是一样,在前面的实例代码中,只给了两个链接。通过检查实例网站的翻页按钮,我们可以看到它的代码

<ul class="pager">
    <li class="next">
        <a href="/page/2/">Next <span aria-hidden="true">&rarr;</span></a>
    </li>
</ul>

在shell里这样调试,首先获取a标签

>>> response.css('li.next a').extract_first()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'

然后再通过属性href来获取地址

>>> response.css('li.next a::attr(href)').extract_first()
'/page/2/'

下面通过这段代码来实现获取所有翻页链接以及所有网页的信息

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').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

这段代码仔细阅读一下也很好理解,只给定一个初始网页,再获取第一页数据之后,获取翻页链接,此时翻页链接的地址为相对地址,就像'/page/2/'这样,我们在通过urljoin()方法,使它成为一个绝对地址,然后再利用scrapy对绝对地址发送一个新的request请求。

还有一个捷径直接通过相对地址也可以直接发送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').extract_first(),
                'author': quote.css('span small::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

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

试一下同样也可以运行,甚至我们还可以简化

把后面获取翻页链接的代码替换为

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

又由于它本身就是a标签我们还可以利用它这个特性再继续简化,把上面的代码再改成

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

这样下来,你的代码就简介了很多,最后你也就通过了下面的代码就抓取了一个网站的所有信息。现在是不是一点点发现了scrapy的魅力了,之前我们抓取完全相同的网站华师信管官网,写了大概大几百行代码,现在我们利用了一下scrapy,十行代码搞定

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').extract_first(),'author': quote.css('span small::text').extract_first(),'tags': quote.css('div.tags a.tag::text').extract(), }
        for a in response.css('li.next a'):
            yield response.follow(a, callback=self.parse)

不信你再回去瞅瞅我们第一篇纯手写的爬虫一个简单的爬虫——新闻爬虫

今天就到这了,关注一波吧

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值