Python爬蟲深造篇(四)——Scrapy爬蟲框架啟動一個真正的專案

何壹時發表於2021-11-08

一、前情提要

經過前面的學習,我們初識了 Scrapy 框架,通過 Scrapy 提供的互動工具,我們在命令列中體驗了 Scrapy 中的 CSS 選擇器

最重要的幾個點是:. 代表 class,# 代表 id,比如 div.book 代表 class 包含 book 的 div 元素,div#book 代表 id 為 book 的 div 元素。在有層級關係時,用 > 號連線直接下一級的元素,用空格連線所有下級的元素。

這篇文章將帶大家將走進 Scrapy,學習如何啟動一個真正意義上的 Scrapy 專案。

二、走進scrapy

和之前一樣,我們 Win + R 開啟 cmd 命令列,在命令列輸入 scrapy 檢查框架是否正常顯示,然後我們再輸入explorer . 開啟執行命令所在的資料夾↓

注意:explorer 命令後面有一個點,這個點代表當前資料夾,同時要注意 explorer 命令和點之間有一個空格。

在這裡插入圖片描述
之後在命令列中輸入下面的命令,讓 Scrapy 建立一個名叫 appinn 專案:

scrapy startproject appinn

在這裡插入圖片描述
這時你會發現剛剛開啟的資料夾裡多了一個叫做 appinn 的資料夾,它的目錄結構如下:

appinn
├── appinn         # 專案程式碼所在的目錄
│   ├── __init__.py
│   ├── items.py     # 定義資料的格式
│   ├── middlewares.py
│   ├── pipelines.py   # 處理資料、輸出到檔案等等
│   ├── settings.py    # 一些設定
│   └── spiders      # 爬蟲所在的目錄
│       └── __init__.py
└── scrapy.cfg

在這裡插入圖片描述
上面標紅的就是需要大家留心的!
然後我們還需要在命令列裡輸入 cd appinn,進入 appinn 資料夾。
在這裡插入圖片描述

注意:下面的操作都需要保證命令列在專案裡哦,如果出錯,請先檢查一下自己是不是在專案根目錄裡。

下面我們來跟隨一個簡單的專案實戰,理解這些檔案的作用
我們開啟小眾軟體的 Windows 軟體推薦頁:https://www.appinn.com/category/windows/
在這裡插入圖片描述
然後隨便開啟一篇文章
這次我們要爬取的是 Windows 版面下所有文章的標題、時間、作者、分數、正文↓
在這裡插入圖片描述
接下來,我們來分別看看 Scrapy 生成的這些檔案在爬蟲中具體起到了什麼作用。

1、items.py

items.py 是記錄我們想要的資料格式的檔案。

在確定了我們要爬的資料是什麼之後,就可以來定義資料的格式。我們資料的格式可以定義在 items.py 裡。建立專案時 Scrapy 給這個檔案自動生成了如下的程式碼↓
我們利用編輯器開啟 items.py 檔案

import scrapy

class AppinnItem(scrapy.Item):
  # define the fields for your item here like:
  # name = scrapy.Field()
  pass

按照我們需要的資料標題、時間、作者、分數、正文,分別把他們叫做 title、time、author、score 和 content。於是把 items.py 檔案裡的程式碼改成這樣↓

import scrapy

class Article(scrapy.Item):
  title = scrapy.Field()  # 標題
  time = scrapy.Field()   # 時間
  author = scrapy.Field()   # 作者
  score = scrapy.Field()  # 分數
  content = scrapy.Field()  # 內容

通過 scrapy.Field() 方法,我們定義出了所有需要的欄位,這樣就定義好了我們要的資料格式:一個叫做 Article 的 Item。Item 是一個和字典類似的東西,使用它而不用字典的理由就是:在爬取網頁的時候常常出現資料缺失、內容錯誤之類的問題,使用 Item 可以更好的處理這些問題。

2、spiders 目錄

spiders 目錄裡儲存了我們建立的爬蟲。

在命令列裡執行下面的命令並回車,它會幫我們建立一個叫做 article 的爬蟲,並且只爬取 www.appinn.com 下的網頁↓

scrapy genspider article www.appinn.com

在這裡插入圖片描述
執行成功後可以看到在 spiders 目錄裡多出了一個 article.py,檔案裡有自動生成的程式碼↓

import scrapy

class ArticleSpider(scrapy.Spider):
  name = 'article'
  allowed_domains = ['www.appinn.com']
  start_urls = ['http://www.appinn.com/']

  def parse(self, response):
    pass

注意?
name :是專案中每個爬蟲唯一的名字,用來區分不同的爬蟲。
allowed_domains :是允許爬取的域名,如果請求的連結不在這個域名下,那麼這些請求將會被過濾掉。
start_urls :是初始請求地址的列表,也就是一開始就爬取的頁面地址列表。
parse() :方法是預設的解析方法,負責解析返回的響應、提取資料或者生成下一步要處理的請求。

現在我先把程式碼進行拆分說明!後面會有完整程式碼!

首先我們把 start_urls 改成我們需要的開始連結↓

start_urls = ['https://www.appinn.com/category/windows/']

接著引入我們剛剛寫好的 Items.py↓

from appinn.items import Article

下面是加一個解析文章的方法,用來解析文章詳情頁(如:https://www.appinn.com/videocutter-and-mp3cutter-yyzsoft/),把標題、時間、作者、分數、正文取出來。我們把這個方法叫做 parse_article,具體程式碼如下↓

def parse_article(self, response):
  article = Article()
  # 從 response 裡提取出標題、時間、作者、分數和內容
  # 並將它們都存到 article 這個 item 裡
  article['title'] = response.css('h1.title::text').get()
  article['time'] = response.css('span.thetime span::text').get()
  article['author'] = response.css('span.theauthor span a::text').get()
  article['score'] = response.css('em strong::text').get()
  contents = response.css('div.post-single-content *::text').getall()
  article['content'] = '\n'.join(contents)
  # 給出結果
  yield article

注意:上一篇中我們介紹過 yield,它和 return 類似,但不會結束函式或方法,而能夠多次返回內容。

然後是預設的解析方法 parse(),我們用它來解析列表頁↓

def parse(self, response):
  # 找到所有文章的連結,通知 Scrapy 用 parse_article 方法解析
  for article_url in response.css('article h2.title a::attr(href)').getall():
    if not article_url:
      continue
    # 後續請求和解析
    yield response.follow(article_url, self.parse_article)

  # 找到下一頁的連結,通知 Scrapy 用 parse 方法解析
  next_page = response.css('a.next::attr(href)').get()
  if next_page:
    # 後續請求和解析
    yield response.follow(next_page, self.parse)

response.follow() 方法用於生成下一個請求和資料解析,第一個引數是下一個頁面的地址,第二個是用於解析從第一個引數地址獲取到網頁原始碼資料的方法。上面解析文章用了 parse_article() 方法,解析文章列表頁用了 parse() 方法。

到這裡,我們 spiders 目錄裡的爬蟲就寫好了。完整版的 article.py 如下↓

import scrapy
from appinn.items import Article

class ArticleSpider(scrapy.Spider):
  name = 'article'
  allowed_domains = ['www.appinn.com']
  start_urls = ['https://www.appinn.com/category/windows/']

  def parse(self, response):
    # 找到所有文章的連結,通知 Scrapy 用 parse_article 方法解析
    for article_url in response.css('article h2.title a::attr(href)').getall():
      if not article_url:
        continue
      # 後續請求和解析
      yield response.follow(article_url, self.parse_article)

    # 找到下一頁的連結,通知 Scrapy 用 parse 方法解析
    next_page = response.css('a.next::attr(href)').get()
    if next_page:
      # 後續請求和解析
      yield response.follow(next_page, self.parse)

  def parse_article(self, response):
    article = Article()
    # 從 response 裡提取出標題、時間、作者、分數和內容
    # 並將它們都存到 article 這個 item 裡
    article['title'] = response.css('h1.title::text').get()
    article['time'] = response.css('span.thetime span::text').get()
    article['author'] = response.css('span.theauthor span a::text').get()
    article['score'] = response.css('em strong::text').get()
    contents = response.css('div.post-single-content *::text').getall()
    article['content'] = '\n'.join(contents)
    # 給出結果
    yield article

parse() 方法每次執行時都要完成下面這兩件事↓
找到當前頁面中所有文章的連結,生成解析請求,Scrapy 會用 parse_article() 方法解析文章連結;
找到下一個頁面的連結,生成解析請求,Scrapy 會用 parse() 方法解析它找到的文章列表連結。

3、pipelines.py

pipelines.py 檔案允許我們在得到結果之後,對結果進行一些處理。比如我們不想要分數在 3 以下的文章,就可以在 pipelines.py 裡面做處理。

Scrapy 替我們自動生成的程式碼如下,預設會直接 return item,意思是保留所有的 item↓

class AppinnPipeline(object):
  def process_item(self, item, spider):
    return item

這個 process_item() 方法就是得到結果之後處理 item 的方法,在這裡做一些過濾或者對 item 做一些修改都是可以的。在這個方法裡 raise DropItem() 可以去掉我們不想要的 item,所以我們把它改成下面這樣來去掉 3 分以下的文章↓

from scrapy.exceptions import DropItem

class AppinnPipeline(object):
  def process_item(self, item, spider):
    if item.get('score'):
      # 把 item 的 score 變成整數
      item['score'] = int(item['score'])
      if item['score'] < 3:
        raise DropItem('去掉 3 分以下的文章')
    return item

前面說過 item 和字典類似,你可以簡單的認為 item 就是字典,使用 get() 方法可以獲取其中的內容。當該鍵不存在時返回 None,而非報錯。

4、settings.py

settings.py 是整個專案的配置檔案,這個檔案裡可以設定爬取併發個數、等待時間、輸出格式、預設 headers 等等。

我們可以寫一些配置如下↓

BOT_NAME = 'appinn'

SPIDER_MODULES = ['appinn.spiders']
NEWSPIDER_MODULE = 'appinn.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'appinn (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# 上面都是自動生成的,下面開始是我們自己定義的
# 要使用的 pipeline
ITEM_PIPELINES = {
  'appinn.pipelines.AppinnPipeline': 300,  # 300 表示順序,pipeline 有多個時,數字越小越先執行
}
FEED_FORMAT = 'csv'  # 最後輸出的檔案格式
FEED_URI = 'appin_windows_apps.csv'  # 最後輸出的檔名

# 為了避免對被爬網站造成太大的壓力,我們啟動自動限速,設定最大併發數為 5
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 5

5、執行爬取

在命令列輸入 scrapy crawl article 並回車,爬蟲就開始執行了。由於我們在設定檔案裡配置了自動限速,所以我們稍等幾分鐘。
在這裡插入圖片描述
自動爬取過程↓
在這裡插入圖片描述

完成後我們可以在命令列裡輸入 explorer . 開啟當前所在的 appinn 資料夾,這時我們可以找到一個名為 appin_windows_apps.csv 的檔案,這就是最後的結果↓
在這裡插入圖片描述

本次分享到此結束,謝謝大家閱讀!!

相關文章