scrapy爬蟲教程摘要(一)——基本流程

語言: CN / TW / HK

簡介

scrapy是一個基於python的爬蟲框架,提供了一套比較完整的爬蟲解決方案,包括模擬cookie,referer,ajax等,並且支援代理,失敗重試等爬蟲攻防操作。可以讓你專注於資料本身而不需要處理太多底層的東西。

今天整理一部分操作要點在這裡以供速查和快速入門。

專案

既然scrapy是一個框架,我們需要先建立專案資料夾

scrapy startproject tutorial

第三個引數就是專案的名字,建議按網站建立不同專案,因為一個專案共享一套配置,包括資料匯出格式,使用哪些中介軟體等,如果不同網站的爬蟲放在同一個專案可能需要反覆修改這些配置導致混亂。但是一個專案可以有多個爬蟲,比如爬列表的,爬詳情的,爬標籤的……

``` tutorial/ scrapy.cfg # 部署配置檔案

tutorial/             # 專案程式碼資料夾
    __init__.py

    items.py          # 專案item類

    middlewares.py    # 專案中介軟體類

    pipelines.py      # 專案流水線類

    settings.py       # 配置檔案

    spiders/          # 放置各種爬蟲程式碼
        __init__.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)

```

這個例子來自官方文件,展示了一個爬蟲最最基本的兩個部分。傳送請求和分析資料。分別對應 start_requests 和 parse 兩個方法。這就是我前面說的使用scrapy只需要專注於資料本身,就是這兩塊。後面的各種改進也是圍繞這兩塊展開。

另外有一個關鍵屬性就是name,表示爬蟲的名字,是爬蟲的唯一標識。我們在啟動這個爬蟲的時候需要用到。

scrapy crawl quotes

這個命令就是執行這個爬蟲了。start_requests負責發起請求,他一定是yield一個Request物件,Request需要指定回撥是parse。parse接收response物件,包含所有的響應資訊,這個例子咱們不做更多的操作,直接儲存返回資料為html。後面展示怎麼從response中提取我們需要的資訊。

選擇器

官方提供了一種學習提取資料的方法是用shell模式

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

這樣可以在shell裡面互動式編碼,檢視提取資料的結果。咱們先介紹css選擇器,因為只要有一點前端基礎的人都懂css選擇器的語法。

```

response.css('title') [] response.css('title::text').getall() ['Quotes to Scrape'] response.css('title').getall() ['Quotes to Scrape'] response.css('title::text').get() 'Quotes to Scrape' response.css('title::text')[0].get() 'Quotes to Scrape' response.css('title::text').re(r'Quotes.*') ['Quotes to Scrape'] response.css('title::text').re(r'Q\w+') ['Quotes'] response.css('title::text').re(r'(\w+) to (\w+)') ['Quotes', 'Scrape'] tags = quote.css("div.tags a.tag::text").getall() tags ['change', 'deep-thoughts', 'thinking', 'world'] response.css('li.next a::attr(href)').get() '/page/2/' ```

這裡有兩個css選擇器的擴充套件語法就是 ::text 和 ::attr 分別獲取標籤文字和屬性。屬性還可以用這種方式獲得:

```

response.css('li.next a').attrib['href'] '/page/2' ```

get方法還可以指定預設值

response.css(query).get(default='').strip()

用css選擇器很容易定位到我們需要的資料,當然scrapy還提供另一種選擇器就是xpath。這個也很經典,但是現在好像使用場景遠遠少於css,所以有興趣的朋友自行學習這種新的語法。

返回資料和分頁

``` 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:
        next_page = response.urljoin(next_page)
        yield scrapy.Request(next_page, callback=self.parse)

```

parse方法中yield一個字典就可以返回資料了,我們在執行的時候可以用 -o 引數指定輸出到一個檔案。預設的輸出格式是jsonline,也就是一行一個json字串,檔案輸出的格式還可以是csv, json, xml。json與jsonline的區別是json是輸出一個json字串包含所有結果。

scrapy crawl quotes -o quotes.json

如果要繼續爬取下一頁也可以在parse中產生下一頁的request,不過在請求下一頁的時候要注意相對路徑的問題,上例得到的url就是一個相對路徑,所以需要用response.urljoin方法來轉為絕對路徑。

結語

至此已經可以爬取一個分頁列表的資料並把它儲存在檔案裡了。如果一個網站沒有設定反爬的話這裡是完全沒問題了。

Reference

檢視原文>>

官方文件>>