官术网_书友最值得收藏!

1.3 編寫第一個Scrapy爬蟲

為了幫助大家建立對Scrapy框架的初步印象,我們使用它完成一個簡單的爬蟲項目。

1.3.1 項目需求

在專門供爬蟲初學者訓練爬蟲技術的網站(http://books.toscrape.com)上爬取書籍信息,如圖1-1所示。

圖1-1

該網站中,這樣的書籍列表頁面一共有50頁,每頁有20本書,第一個例子應盡量簡單。我們下面僅爬取所有圖書(1000本)的書名和價格信息。

1.3.2 創建項目

首先,我們要創建一個Scrapy項目,在shell中使用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命令查看項目目錄下的文件,顯示如下:

        $ tree example
        example/
        ├── example
        │  ├── __init__.py
        │  ├── items.py
        │  ├── middlewares.py
        │  ├── pipelines.py
        │  ├── settings.py
        │  └── spiders
        │     └── __init__.py
        └── scrapy.cfg

隨著后面逐步深入學習,大家會了解這些文件的用途,此處不做解釋。

1.3.3 分析頁面

編寫爬蟲程序之前,首先需要對待爬取的頁面進行分析,主流的瀏覽器中都帶有分析頁面的工具或插件,這里我們選用Chrome瀏覽器的開發者工具(Tools→Developer tools)分析頁面。

1.數據信息

在Chrome瀏覽器中打開頁面http://books.toscrape.com,選中其中任意一本書并右擊,然后選擇“審查元素”,查看其HTML代碼,如圖1-2所示。

圖1-2

可以看到,每一本書的信息包裹在<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">元素的文本中,如<p class="price_color">£51.77</p>。

2.鏈接信息

圖1-3所示為第一頁書籍列表頁面,可以通過單擊next按鈕訪問下一頁,選中頁面下方的next按鈕并右擊,然后選擇“審查元素”,查看其HTML代碼,如圖1-3所示。

圖1-3

可以發現,下一頁的URL在ul.pager > li.next > a元素的href屬性中,是一個相對URL地址,如<li class="next"><a href="catalogue/page-2.html">next</a></li>。

1.3.4 實現Spider

分析完頁面后,接下來編寫爬蟲。在Scrapy中編寫一個爬蟲,即實現一個scrapy.Spider的子類。

實現爬蟲的Python文件應位于exmaple/spiders目錄下,在該目錄下創建新文件book_spider.py。然后,在book_spider.py中實現爬蟲BooksSpider,代碼如下:

        # -*- 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>
              next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
              if next_url:
                # 如果找到下一頁的URL,得到絕對路徑,構造新的Request對象
                next_url = response.urljoin(next_url)
                yield scrapy.Request(next_url, callback=self.parse)

如果上述代碼中有看不懂的部分,大家不必擔心,更多詳細內容會在后面章節學習,這里只要先對實現一個爬蟲有個整體印象即可。

下面對BooksSpider的實現做簡單說明。

● name屬性

一個Scrapy項目中可能有多個爬蟲,每個爬蟲的name屬性是其自身的唯一標識,在一個項目中不能有同名的爬蟲,本例中的爬蟲取名為’books'。

● start_urls屬性

一個爬蟲總要從某個(或某些)頁面開始爬取,我們稱這樣的頁面為起始爬取點,start_urls屬性用來設置一個爬蟲的起始爬取點。在本例中只有一個起始爬取點'

● parse方法

當一個頁面下載完成后,Scrapy引擎會回調一個我們指定的頁面解析函數(默認為parse方法)解析頁面。一個頁面解析函數通常需要完成以下兩個任務:

? 提取頁面中的數據(使用XPath或CSS選擇器)。

? 提取頁面中的鏈接,并產生對鏈接頁面的下載請求。

頁面解析函數通常被實現成一個生成器函數,每一項從頁面中提取的數據以及每一個對鏈接頁面的下載請求都由yield語句提交給Scrapy引擎。

1.3.5 運行爬蟲

完成代碼后,運行爬蟲爬取數據,在shell中執行scrapy crawl <SPIDER_NAME>命令運行爬蟲’books',并將爬取的數據存儲到csv文件中:

        $ scrapy crawl books -o books.csv
        2016-12-27 15:19:53 [scrapy] INFO: Scrapy 1.3.3 started (bot: example)
        2016-12-27 15:19:53 [scrapy] INFO: INFO: Overridden settings: {'BOT_NAME': 'example',
    'SPIDER_MODULES': ['example.spiders'], 'ROBOTSTXT_OBEY': True, 'NEWSPIDER_MODULE':
    'example.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)  (referer: None)
       2016-12-27 15:20:02 [scrapy] DEBUG: Crawled (200)  (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)

等待爬蟲運行結束后,在books.csv文件中查看爬取到的數據,代碼如下:

  $sed-n'2, $p'books.csv|cat-n         # 不顯示第一行的csv頭部
      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

從上述數據可以看出,我們成功地爬取到了1000本書的書名和價格信息(50頁,每頁20項)。

主站蜘蛛池模板: 玛曲县| 万山特区| 惠州市| 金坛市| 云安县| 永和县| 民县| 高平市| 延寿县| 盐津县| 广元市| 和田县| 乌鲁木齐县| 太保市| 德州市| 敦煌市| 岫岩| 织金县| 北海市| 泽普县| 平利县| 康平县| 喀什市| 浪卡子县| 岱山县| 中牟县| 富锦市| 邛崃市| 名山县| 奉化市| 伊川县| 潜山县| 伊通| 新河县| 莲花县| 南汇区| 汶上县| 黄陵县| 永城市| 阿拉善盟| 法库县|