继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

[硕.Love Python] 编写第一个scrapy爬虫

程序员硕
关注TA
已关注
手记 19
粉丝 1.7万
获赞 886
编写第一个scrapy爬虫

我们首先来看一下, 一个网络爬虫的基本任务有如下三点:

1. 下载页面

我们知道一个网页的内容本质上就是一个html文本, 我们爬取一个网页第一步就是根据网页的url先下载这个html文本.

2. 提取数据

当我们下载好一个网页(html)后, 就要对网页中的内容进行分析, 并提取出我们感兴趣的数据, 数据可以以很多形式保持起来, 比如将数据以某种格式(csv, json)写入文件中, 或存储到数据库(mysql, mangodb).

3. 提取链接

通常我们想要获取的数据并不在一个页面中, 而是分布在一个网站的多个页面中, 我们可以通过当前网页的链接找到它们. 那接下来我们就要分析出这些我们需要的链接, 把他们提取出来. 然后对新页面进行爬取(循环1-3步骤).

了解了爬虫的基本任务以后, 我们就来看一个简单scrapy爬虫的例子.

toscrape.com是专门用来我们练习爬虫技术的网站, 在第一个爬虫例子中, 我们爬取在http://books.toscrape.com/网站上的书籍信息(名字和价格).

1.创建项目

首先我们要创建一个scrapy工程, 使用scrapy startproject命令.

$ scrapy startproject example

输出:

New Scrapy project 'example', using template directory 
'/usr/local/lib/python3.4/dist-packages/scrapy/templates/project', created in:
/home/liushuo/book/example

You can start your first spider with:
cd example
scrapy genspider example example.com

我们创建好了一个工程名字叫example, 我们可以用tree命令看下新创建出来的工程目录example.

$ tree example

输出:

example/
├── example
│   ├── __init__.py
│   ├── items.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       └── __init__.py
└── scrapy.cfg
2.分析页面

编写爬虫之前, 我们对需要待爬取的页面进行分析, 使用Chrome浏览器打开页面.
http://books.toscrape.com/

  1. 数据信息:

    选中任意一本书, 使用Chrome的审查元素(inspect elements)工具页面的html源码. 如下图1-1.
    图片描述
    我们看到, 每一本书的信息包裹在<article class="product_pod">中:

    • 书名信息在其下h3 > a元素的title属性中, 如:

      <a href="catalogue/a-light-in-the-attic_1000/index.html" title="A Light in the Attic">A Light in the ...</a>

    • 书价信息在其下<p class="price_color">TEXT中, 如:

      <p class="price_color">£51.77</p>

  2. 链接信息

    我们当前看到的第一页书单, 可以通过点击下一页按钮访问下一页, 我们选中页面下方的next按钮, 使用审查元素. 如下图1-2:

    图片描述

    我们看到下一页的url在ul.pager > li.next > a里面, 一个相对地址catalogue/page-2.html.

    <li class="next"><a href="catalogue/page-2.html">next</a></li>

2.实现Spider

接下来我们就来写一个爬虫, 我们需要在example/exmaple/spiders目录下创建一个实现爬虫的python文件, 我们这里取名叫做book_spider.py. 在scrapy中一个爬虫对应于一个scrapy.Spider的子类, 我们在book_spider.py中实现它.

# -*- coding: utf-8 -*-
import scrapy

class BooksSpider(scrapy.Spider):
    # 每一个爬虫的唯一标识
    name = "books"

    # 定义爬虫的爬取的起始点, 起始点可以是多个, 我们这里是一个.
    start_urls = ['http://books.toscrape.com/']

    def parse(self, response): 
        # 提取数据:
        # 每一本书的信息是在<article class="product_pod">中, 我们使用
        # css()方法, 找到所有这样的article元素, 并依次迭代.
        for book in response.css('article.product_pod'):
            # 书名信息在article > h3 > a元素的title属性里.
            # 例如: <a title="A Light in the Attic">A Light in the ...</a>
            name = book.xpath('./h3/a/@title').extract_first()

            # 书价信息在 <p class="price_color">的TEXT中.
            # 例如: <p class="price_color">£51.77</p>
            price = book.css('p.price_color::text').extract_first()
            yield {
                'name': name,
                'price': price,
            }

        # 提取链接: 
        # 下一页的url在ul.pager > li.next > a里面.
        # 例如: <li class="next"><a href="catalogue/page-2.html">next</a></li>
        nextPage = response.css('ul.pager li.next a::attr(href)').extract_first()
        if nextPage:
            # 如果找到下一页的url, 得到绝对路径, 构造新的Request对象.
            nextPage = response.urljoin(nextPage)
            yield scrapy.Request(nextPage, callback=self.parse)

在上面代码中, 我们定义了BooksSpider类实现一个爬虫:

  • name属性

    一个scrapy项目中可能有多个爬虫, 每一个爬虫通过定义name属性(string类型)来标识自身, 在一个项目中不能有同名的爬虫, 我们例子中的爬虫取名为'books'.

  • start_urls属性

    设定爬虫从哪个(或哪些)页面最开始爬取, scrapy会通过Request下载这些页面. 在我们的例子中只有一个爬取的起始点'http://books.toscrape.com/'.

  • parse方法

    当某一个页面下载好后, scrapy框架会回调parse方法(默认情况下)来解析页面, 在这个方法中应实现提取数据和对新页面请求(链接地址)的逻辑.<br>

    通常我们利用浏览器审查页面html源码的工具来分析页面, 找到我们感兴趣数据和其他包含此类数据的页面的链接地址, 在scrapy中使用选择器(Selector)提取这些数据, 选择器可以用CSS或Xpath表达式描述数据在html文本中的位置(css或xpath方法), 然后将数据提取(extract方法). 对于数据我们yield返回一个数据项, 其后scrapy框架会将这条数据保存; 对于页面链接地址, 我们yield返回一个Request对象, 其后scrapy框架会请求下载这个新页面.

3.运行爬虫

实现好爬虫以后, 接下来我们就要运行这个爬虫进行爬取数据了. 我们工程目录执行下面在shell中执行scrapy crawl <SPIDER_NAME>命令运行我们的爬虫books, 并将爬取的数据存储到csv文件中:

$ scrapy crawl books -o books.csv
2016-12-27 15:19:53 [scrapy] INFO: Scrapy 1.2.1 started (bot: toscrape)
2016-12-27 15:19:53 [scrapy] INFO: Overridden settings: {'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['toscrape.spiders'], 'FEED_URI': 'books.csv', 'FEED_FORMAT': 'csv', 'BOT_NAME': 'toscrape', 'NEWSPIDER_MODULE': 'toscrape.spiders'}
2016-12-27 15:19:53 [scrapy] INFO: Enabled extensions:
['scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.feedexport.FeedExporter',
 'scrapy.extensions.logstats.LogStats']
2016-12-27 15:19:53 [scrapy] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2016-12-27 15:19:53 [scrapy] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2016-12-27 15:19:53 [scrapy] INFO: Enabled item pipelines:
[]
2016-12-27 15:19:53 [scrapy] INFO: Spider opened
2016-12-27 15:19:53 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-27 15:19:53 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-27 15:20:01 [scrapy] DEBUG: Crawled (404) <GET http://books.toscrape.com/robots.txt> (referer: None)
2016-12-27 15:20:02 [scrapy] DEBUG: Crawled (200) <GET http://books.toscrape.com/> (referer: None)
2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
{'name': 'A Light in the Attic', 'price': '£51.77'}
2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
{'name': 'Tipping the Velvet', 'price': '£53.74'}
2016-12-27 15:20:02 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/>
{'name': 'Soumission', 'price': '£50.10'}

... <省略中间部分输出> ...

2016-12-27 15:21:30 [scrapy] DEBUG: Scraped from <200 http://books.toscrape.com/catalogue/page-50.html>
{'name': '1,000 Places to See Before You Die', 'price': '£26.08'}
2016-12-27 15:21:30 [scrapy] INFO: Closing spider (finished)
2016-12-27 15:21:30 [scrapy] INFO: Stored csv feed (1000 items) in: books.csv
2016-12-27 15:21:30 [scrapy] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 14957,
 'downloader/request_count': 51,
 'downloader/request_method_count/GET': 51,
 'downloader/response_bytes': 299924,
 'downloader/response_count': 51,
 'downloader/response_status_count/200': 50,
 'downloader/response_status_count/404': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2016, 12, 27, 7, 21, 30, 10396),
 'item_scraped_count': 1000,
 'log_count/DEBUG': 1052,
 'log_count/INFO': 9,
 'request_depth_max': 49,
 'response_received_count': 51,
 'scheduler/dequeued': 50,
 'scheduler/dequeued/memory': 50,
 'scheduler/enqueued': 50,
 'scheduler/enqueued/memory': 50,
 'start_time': datetime.datetime(2016, 12, 27, 7, 19, 53, 194334)}
2016-12-27 15:21:30 [scrapy] INFO: Spider closed (finished)

接下来我们就可以使用任意工具(如excel等), 来看一下我们爬取的数据了, 我们这里使用cat命令:

$ sed -n '2,$p' books.csv | cat -n
     1  A Light in the Attic,£51.77
     2  Tipping the Velvet,£53.74
     3  Soumission,£50.10
     4  Sharp Objects,£47.82
     5  Sapiens: A Brief History of Humankind,£54.23
     6  The Requiem Red,£22.65
     7  The Dirty Little Secrets of Getting Your Dream Job,£33.34

    ... <省略中间部分输出> ...

   995  Beyond Good and Evil,£43.38
   996  Alice in Wonderland (Alice's Adventures in Wonderland #1),£55.53
   997  "Ajin: Demi-Human, Volume 1 (Ajin: Demi-Human #1)",£57.06
   998  A Spy's Devotion (The Regency Spies of London #1),£16.97
   999  1st to Die (Women's Murder Club #1),£53.98
  1000  "1,000 Places to See Before You Die",£26.08

除去第一行的csv头部以外, 我们爬取了1000项书名和价格的数据(50个页, 每页20项).

打开App,阅读手记
26人推荐
发表评论
随时随地看视频慕课网APP

热门评论

你好,我抓到的有乱码,很费解是什么问题,找了好些方法束手无策

查看全部评论