shiqi

shiqi

Study GIS, apply to world
twitter
github
bento
jike

Python 爬蟲

一、爬蟲初印象#

image

在互聯網的廣闊世界裡,數據如同寶藏般散落各處。而爬蟲,就像是一位勤勞的尋寶者,能夠按照特定規則,自動地在網頁間穿梭,抓取我們所需的信息。簡單來說,它是一段能自動獲取網頁數據的程序或腳本,其正式名稱是網絡爬蟲(Web Crawler),也常被稱為網頁蜘蛛、網絡機器人。

爬蟲在數據獲取方面扮演著舉足輕重的角色。如今,數據已成為企業和研究人員決策的關鍵依據,而爬蟲則是獲取大量數據的高效手段。它的應用場景極為廣泛,在數據分析領域,通過爬蟲採集社交媒體平台上的用戶評論和行為數據,能夠助力企業精準洞察用戶需求與市場趨勢,為產品優化和營銷策略制定提供有力支撐。在競品調研中,爬蟲可以定期抓取競爭對手的產品信息、價格動態以及促銷活動等,幫助企業及時調整自身策略,保持競爭力。此外,在學術研究、新聞資訊聚合等方面,爬蟲也發揮著不可替代的作用。

二、環境搭建與基礎語法#

2.1 Python 安裝與配置#

Python 是爬蟲開發的首選語言,其簡潔的語法和豐富的庫能夠極大地簡化開發過程。首先,我們需要從 Python 官方網站(https://www.python.org/downloads/)下載適合你操作系統的安裝包。在下載頁面,你可以看到各種版本的 Python,建議選擇最新的穩定版本。下載完成後,運行安裝包,在安裝向導中,務必勾選 “Add Python to PATH” 選項,這一步非常關鍵,它能確保 Python 可在系統的任何路徑下被調用。

安裝完成後,可以通過在命令提示符(CMD)中輸入python --version來驗證是否安裝成功。如果成功安裝,你將看到 Python 的版本號信息。此外,還可以輸入python進入 Python 交互式環境,在這裡可以直接編寫和執行 Python 代碼,體驗 Python 的魅力。

2.2 開發工具選擇#

一個好的開發工具能夠顯著提高開發效率。在爬蟲開發中,PyCharm 是一款備受青睞的集成開發環境(IDE)。它具有強大的代碼編輯功能,如代碼自動補全、語法高亮、代碼導航等,能讓你在編寫代碼時更加得心應手。同時,PyCharm 對 Python 的各種庫和框架有很好的支持,方便進行項目管理和調試。

除了 PyCharm,還有其他一些不錯的選擇,如 Visual Studio Code(VS Code)。它是一款輕量級但功能強大的代碼編輯器,通過安裝 Python 插件,同樣能實現高效的 Python 開發。VS Code 具有良好的擴展性和跨平台性,適合喜歡簡潔開發環境的開發者。

2.3 Python 基礎語法回顧#

在正式開始爬蟲開發前,回顧一下 Python 的基礎語法是很有必要的。這包括數據類型、控制語句和函數等。

Python 有多種基本數據類型,例如整數(int)、浮點數(float)、字符串(str)、布爾值(bool)等。不同的數據類型在存儲和操作數據時各有特點。比如,字符串用於存儲文本信息,你可以通過索引和切片操作來獲取字符串中的特定字符或子串。示例代碼如下:

name = "爬蟲小能手"

print(name\[0])  # 輸出第一個字符

print(name\[2:5])  # 輸出從第三個字符到第五個字符的子串

控制語句是程序邏輯的重要組成部分,常見的有條件語句(if - elif - else)和循環語句(for、while)。條件語句用於根據不同的條件執行不同的代碼塊,循環語句則用於重複執行某段代碼。例如,使用 for 循環遍歷一個列表:

fruits = \["蘋果", "香蕉", "橙子"]

for fruit in fruits:

      print(fruit)

函數是將一段可重複使用的代碼封裝起來的工具,它可以提高代碼的復用性和可讀性。在 Python 中,你可以使用def關鍵字定義函數,例如:

def add\_numbers(a, b):

      return a + b

result = add\_numbers(3, 5)

print(result)  # 輸出8

通過對這些基礎語法的掌握,我們為後續的爬蟲開發奠定了堅實的基礎。

三、爬蟲基礎原理與流程#

image

3.1 HTTP 協議解析#

HTTP 協議,即超文本傳輸協議,是爬蟲與網頁伺服器進行通信的基礎。它就像是爬蟲與伺服器之間的通用語言,規定了雙方如何進行數據的請求和傳輸。

HTTP 請求主要由請求行、請求頭、請求體(可選)組成。請求行包含了請求方法、URL 和 HTTP 版本。常見的請求方法有 GET 和 POST。GET 方法通常用於從伺服器獲取資源,比如訪問網頁時,瀏覽器會向伺服器發送 GET 請求,獲取網頁的 HTML 內容。在使用 GET 請求時,參數會附加在 URL 的末尾,以鍵值對的形式呈現,例如https://example.com/search?q=爬蟲&page=1,這種方式使得參數在 URL 中可見,因此不太適合傳輸敏感信息。

POST 方法則常用於向伺服器提交數據,比如登錄表單、提交評論等操作。與 GET 不同,POST 請求的參數放在請求體中,對用戶不可見,安全性相對較高。例如,在登錄時,用戶名和密碼會通過 POST 請求發送到伺服器,請求體中可能包含類似username=admin&password=123456的內容。

HTTP 響應由狀態行、響應頭、響應體組成。狀態行中的狀態碼能直觀地反映請求的處理結果。例如,200 表示請求成功,伺服器成功返回了所請求的資源;404 表示請求的資源不存在,可能是 URL 輸入錯誤或頁面已被刪除;500 表示伺服器內部出現錯誤。響應頭包含了關於響應的一些元信息,如內容類型(如text/html表示返回的是 HTML 頁面)、內容長度等。而響應體則是我們真正想要獲取的數據,比如網頁的 HTML 代碼、JSON 格式的數據等。

3.2 爬蟲工作流程#

爬蟲的工作流程可以概括為發起請求、獲取響應、解析數據和保存數據這幾個關鍵步驟。

首先,爬蟲會根據設定的 URL,使用 HTTP 庫(如 Python 中的requests庫)向目標伺服器發起請求。在這個過程中,為了模擬真實用戶的訪問,可能會設置請求頭,例如User - Agent,它可以告訴伺服器訪問者使用的瀏覽器類型和操作系統等信息。例如,以下代碼使用requests庫發起一個 GET 請求:

import requests

url = "https://example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

response = requests.get(url, headers = headers)

伺服器接收到請求後,會返回相應的響應。如果請求成功,我們會得到一個包含狀態碼、響應頭和響應體的響應對象。爬蟲獲取到響應後,接下來就是從響應體中提取出我們需要的數據。這一步需要根據數據的格式選擇合適的解析方法。如果響應體是 HTML 格式,可以使用BeautifulSouplxml等庫進行解析。例如,使用BeautifulSoup解析 HTML 頁面,提取所有的鏈接:

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, 'html.parser')

links = soup.find\_all('a')

for link in links:
  print(link.get('href'))

若響應體是 JSON 格式的數據,可以使用 Python 內置的json模塊進行解析。示例如下:

import json

data = json.loads(response.text)

print(data)

最後,將解析得到的數據保存到本地文件或數據庫中,以便後續的分析和使用。保存到文件的常見格式有文本文件(.txt)、CSV 文件(.csv)、JSON 文件(.json)等。例如,將數據保存為 JSON 文件:

import json

data = \[{"name": "爬蟲", "info": "數據採集工具"}]

with open('data.json', 'w', encoding='utf - 8') as f:
  json.dump(data, f, ensure\_ascii=False, indent=4)

如果需要保存到數據庫,對於關係型數據庫(如 MySQL),可以使用pymysql庫;對於非關係型數據庫(如 MongoDB),可以使用pymongo庫。

四、爬蟲常用庫實戰#

image

4.1 Requests 庫#

Requests 庫是 Python 中用於發送 HTTP 請求的利器,它的 API 簡潔明了,讓我們能夠輕鬆地與網頁伺服器進行交互。在使用 Requests 庫時,首先要確保已經安裝,可以通過pip install requests命令進行安裝。

安裝完成後,就可以在代碼中使用它了。例如,發送一個簡單的 GET 請求來獲取網頁內容:

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      print(response.text)

else:

      print(f"請求失敗,狀態碼: {response.status\_code}")

在這個例子中,requests.get(url)向指定的 URL 發送 GET 請求,並返回一個響應對象response。通過檢查response.status_code,我們可以判斷請求是否成功。如果狀態碼為 200,說明請求成功,response.text中包含了網頁的 HTML 內容。

除了 GET 請求,Requests 庫還支持 POST 請求,用於向伺服器提交數據。例如,模擬登錄表單提交:

import requests

url = "https://www.example.com/login"

data = {

      "username": "your\_username",

      "password": "your\_password"

}

response = requests.post(url, data = data)

print(response.text)

在這段代碼中,data字典包含了登錄所需的用戶名和密碼,requests.post(url, data = data)將這些數據發送到指定的登錄 URL。

此外,還可以通過設置請求頭來模擬不同的瀏覽器訪問,以及處理響應的 JSON 數據、設置請求超時等。例如,設置請求頭:

import requests

url = "https://www.example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

response = requests.get(url, headers = headers)

print(response.text)

在這個例子中,headers字典設置了User - Agent,告訴伺服器我們使用的是 Chrome 瀏覽器。這樣可以避免一些網站因為檢測到非瀏覽器訪問而拒絕請求。

4.2 BeautifulSoup 庫#

BeautifulSoup 庫是專門用於解析 HTML 和 XML 數據的強大工具。它能夠將複雜的 HTML 或 XML 文檔轉換成一個易於遍歷和操作的樹形結構,讓我們可以輕鬆地提取所需的數據。在使用 BeautifulSoup 庫之前,需要先安裝,可以通過pip install beautifulsoup4命令進行安裝。

假設我們已經使用 Requests 庫獲取了網頁的 HTML 內容,接下來就可以使用 BeautifulSoup 庫進行解析。例如:

from bs4 import BeautifulSoup

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      soup = BeautifulSoup(response.text, 'html.parser')

      # 提取所有的鏈接

      links = soup.find\_all('a')

      for link in links:

          print(link.get('href'))

else:

      print(f"請求失敗,狀態碼: {response.status\_code}")

在這段代碼中,BeautifulSoup(response.text, 'html.parser')將獲取到的 HTML 內容解析成一個BeautifulSoup對象souphtml.parser是解析器,這裡使用的是 Python 內置的 HTML 解析器,也可以根據需要選擇其他解析器,如lxmlsoup.find_all('a')用於查找所有的<a>標籤,即鏈接,並通過link.get('href')獲取每個鏈接的href屬性值。

除了通過標籤名查找元素,還可以通過類名、ID 等屬性進行查找。例如,查找具有特定類名的元素:

from bs4 import BeautifulSoup

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      soup = BeautifulSoup(response.text, 'html.parser')

      # 查找類名為 "special - class" 的元素

      special\_elements = soup.find\_all(class\_='special - class')

      for element in special\_elements:

          print(element.get\_text())

else:

      print(f"請求失敗,狀態碼: {response.status\_code}")

在這個例子中,soup.find_all(class_='special - class')查找所有類名為special - class的元素,並通過element.get_text()獲取這些元素的文本內容。

4.3 XPath 語法#

XPath 是一種用於在 XML 和 HTML 文檔中定位和提取元素的語言。它通過定義路徑表達式,能夠精準地選取文檔中的節點或節點集,在爬蟲開發中具有重要的應用。在 Python 中,可以結合lxml庫來使用 XPath 語法。首先,需要安裝lxml庫,通過pip install lxml命令進行安裝。

下面是一個使用 XPath 語法提取網頁數據的示例:

from lxml import etree

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      html = etree.HTML(response.text)

      # 提取所有的 \<p> 標籤的文本內容

      p\_texts = html.xpath('//p/text()')

      for text in p\_texts:

          print(text)

else:

      print(f"請求失敗,狀態碼: {response.status\_code}")

在這段代碼中,etree.HTML(response.text)將獲取到的 HTML 內容轉換為lxmlElement對象htmlhtml.xpath('//p/text()')使用 XPath 表達式//p/text()選取所有<p>標籤內的文本內容。其中,//表示從當前節點開始選擇文檔中的節點,不考慮它們的位置;p是標籤名;/text()表示選取該標籤內的文本。

XPath 語法還支持通過屬性來定位元素。例如,提取具有特定屬性值的元素:

from lxml import etree

import requests

url = "https://www.example.com"

response = requests.get(url)

if response.status\_code == 200:

      html = etree.HTML(response.text)

      # 提取class為 "article - content" 的 \<div> 標籤內的所有鏈接

      links = html.xpath('//div\[@class="article - content"]//a/@href')

      for link in links:

          print(link)

else:

      print(f"請求失敗,狀態碼: {response.status\_code}")

在這個例子中,//div[@class="article - content"]表示選取所有class屬性值為article - content<div>標籤,//a/@href表示在這些<div>標籤內繼續選取所有<a>標籤的href屬性值。

4.4 正則表達式#

正則表達式是一種用於匹配和處理字符串的強大工具,在爬蟲的數據提取中也經常被用到。它通過定義一系列的規則來匹配符合特定模式的字符串。在 Python 中,通過內置的re模塊來支持正則表達式。

例如,假設我們要從一段文本中提取所有的電話號碼,可以使用如下正則表達式:

import re

text = "聯繫電話:13888888888,另一個電話:15666666666"

pattern = r'\d{11}'

phones = re.findall(pattern, text)

for phone in phones:

      print(phone)

在這段代碼中,r'\d{11}'是正則表達式模式。其中,r表示這是一個原始字符串,防止反斜杠字符被轉義;\d表示匹配任何一個數字字符(0 - 9);{11}表示前面的字符(即數字)連續出現 11 次。re.findall(pattern, text)在給定的文本text中查找所有符合正則表達式模式pattern的字符串,並返回一個列表。

正則表達式還可以用於匹配更複雜的模式,如電子郵件地址、URL 等。例如,匹配電子郵件地址:

import re

text = "郵箱:[email protected],另一個郵箱:[email protected]"

pattern = r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'

emails = re.findall(pattern, text)

for email in emails:

      print(email)

在這個例子中,[a-zA-Z0-9_.+-]+表示由字母、數字、下劃線、點、加號和減號組成的一個或多個字符;@是電子郵件地址的固定符號;[a-zA-Z0-9-]+表示由字母、數字和減號組成的一個或多個字符;\.[a-zA-Z0-9-.]+表示一個點後面跟著由字母、數字、點和減號組成的一個或多個字符。這個正則表達式模式能夠準確地匹配常見的電子郵件地址格式。

五、爬蟲進階技巧#

image

5.1 處理反爬蟲機制#

在爬蟲的征程中,我們常常會遭遇網站的反爬蟲機制,這就如同在尋寶路上遇到了重重關卡。不過別擔心,我們有一系列有效的應對策略。

設置請求頭是一個簡單而有效的方法。網站往往會通過檢測請求頭中的User - Agent等信息來判斷請求是否來自爬蟲。我們可以通過模擬真實瀏覽器的請求頭,讓網站誤以為是普通用戶在訪問。例如,在 Python 的requests庫中,可以這樣設置請求頭:

import requests

url = "https://example.com"

headers = {

      "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

}

response = requests.get(url, headers = headers)

這裡的User - Agent字符串模擬了 Chrome 瀏覽器的信息,通過這種方式,可以增加請求的可信度。

使用代理 IP 也是突破反爬蟲限制的重要手段。當我們的 IP 地址因為頻繁請求被網站封禁時,代理 IP 就像是我們的 “替身”,幫助我們繼續訪問網站。可以使用一些免費或付費的代理 IP 服務,在 Python 中,通過requests庫設置代理 IP 的示例如下:

import requests

url = "https://example.com"

proxies = {

      "http": "http://your\_proxy\_ip:your\_proxy\_port",

      "https": "https://your\_proxy\_ip:your\_proxy\_port"

}

response = requests.get(url, proxies = proxies)

在使用代理 IP 時,要注意選擇可靠的代理源,確保代理 IP 的穩定性和可用性。

此外,控制請求頻率也至關重要。如果短時間內向網站發送大量請求,很容易被識別為爬蟲。我們可以通過設置時間間隔,讓請求更加 “溫柔”。例如,使用time模塊中的sleep函數,在每次請求後暫停一段時間:

import requests

import time

url\_list = \["https://example1.com", "https://example2.com", "https://example3.com"]

for url in url\_list:

      response = requests.get(url)

      time.sleep(5)  # 暫停5秒

這樣,每隔 5 秒發送一次請求,降低了被反爬蟲機制檢測到的風險。

5.2 動態網頁抓取#

隨著網頁技術的發展,越來越多的網頁採用了動態加載技術,這給爬蟲帶來了新的挑戰。傳統的直接獲取 HTML 內容的方法,可能無法獲取到動態加載的數據。不過,我們有專門的工具來應對這一情況。

Selenium 是一個強大的自動化測試工具,它可以模擬真實用戶在瀏覽器中的操作,從而獲取動態網頁的完整內容。使用 Selenium,首先需要安裝對應的瀏覽器驅動,以 Chrome 瀏覽器為例,從 ChromeDriver 下載與瀏覽器版本匹配的驅動。安裝完成後,通過pip install selenium安裝 Selenium 庫。以下是使用 Selenium 打開網頁並獲取內容的示例:

from selenium import webdriver

driver = webdriver.Chrome()

driver.get("https://example.com")

# 獲取網頁內容

page\_source = driver.page\_source

print(page\_source)

driver.quit()

在這個示例中,webdriver.Chrome()創建了一個 Chrome 瀏覽器驅動實例,driver.get(url)打開指定的網頁,driver.page_source獲取網頁的源代碼,最後driver.quit()關閉瀏覽器。

除了 Selenium,Scrapy - Splash 也是一個不錯的選擇,它是 Scrapy 框架的一個插件,專門用於處理動態網頁。Splash 是一個基於 JavaScript 渲染的服務,它可以在伺服器端渲染 JavaScript,然後將渲染後的 HTML 返回給爬蟲。使用 Scrapy - Splash 時,需要先安裝 Splash 服務,並在 Scrapy 項目中進行相應的配置。配置完成後,就可以在爬蟲代碼中使用 Splash 來處理動態網頁了。例如,在 Scrapy 的settings.py文件中添加如下配置:

SPLASH\_URL = 'http://localhost:8050'

DOWNLOADER\_MIDDLEWARES = {

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

     'scrapy.downloader.middlewares.httpcompression.HttpCompressionMiddleware': 810,

    'scrapy\_splash.SplashMiddleware': 820,

}

SPIDER\_MIDDLEWARES = {

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy\_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy\_splash.SplashSpiderMiddleware': 725,

}

DUPEFILTER\_CLASS ='scrapy\_splash.SplashAwareDupeFilter'

HTTPCACHE\_STORAGE ='scrapy\_splash.SplashAwareFSCacheStorage'

然後在爬蟲代碼中使用 Splash 的Request對象發送請求:

from scrapy\_splash import SplashRequest

class MySpider(scrapy.Spider):

      name = "my\_spider"

      start\_urls = \["https://example.com"]

      def start\_requests(self):

          for url in self.start\_urls:

              yield SplashRequest(url, self.parse, args={'wait': 5})

      def parse(self, response):

          # 解析網頁內容

          pass

在這個例子中,SplashRequest會將請求發送到 Splash 服務,args={'wait': 5}表示等待 5 秒,確保頁面的 JavaScript 代碼充分渲染後再獲取內容。

5.3 多線程與異步爬蟲#

在數據量較大的情況下,單線程爬蟲的效率可能會比較低。這時,我們可以利用多線程和異步編程技術來提高爬蟲的效率。

多線程爬蟲可以同時開啟多個線程,每個線程負責一個或多個 URL 的請求和數據提取工作,從而大大加快數據採集的速度。在 Python 中,可以使用threading模塊來實現多線程爬蟲。例如:

import threading

import requests

def fetch\_url(url):

      response = requests.get(url)

      print(response.text)

url\_list = \["https://example1.com", "https://example2.com", "https://example3.com"]

threads = \[]

for url in url\_list:

      t = threading.Thread(target = fetch\_url, args = (url,))

      threads.append(t)

      t.start()

for t in threads:

      t.join()

在這段代碼中,threading.Thread(target = fetch_url, args = (url,))創建了一個新的線程,target指定線程要執行的函數,args傳遞函數所需的參數。通過這種方式,多個線程同時對不同的 URL 發起請求,提高了爬蟲的效率。

異步爬蟲則是利用 Python 的異步編程特性,在一個線程中實現非阻塞的 I/O 操作。在等待網絡請求的過程中,程序可以執行其他任務,從而避免了線程的阻塞,提高了資源的利用率。asyncio是 Python 中用於異步編程的標準庫,結合aiohttp庫(用於異步 HTTP 請求),可以實現高效的異步爬蟲。示例代碼如下:

import asyncio

import aiohttp

async def fetch\_url(session, url):

      async with session.get(url) as response:

          return await response.text()

async def main():

      urls = \["https://example1.com", "https://example2.com", "https://example3.com"]

      async with aiohttp.ClientSession() as session:

          tasks = \[fetch\_url(session, url) for url in urls]

          results = await asyncio.gather(\*tasks)

          for result in results:

              print(result)

if \_\_name\_\_ == "\_\_main\_\_":

      asyncio.run(main())

在這個例子中,async def定義了異步函數,await用於等待異步操作的完成。aiohttp.ClientSession()創建了一個 HTTP 會話,tasks列表包含了所有的異步任務,asyncio.gather(*tasks)用於並行運行這些任務,並等待所有任務完成。通過這種方式,實現了高效的異步爬蟲。

六、爬蟲框架應用#

image

6.1 Scrapy 框架#

Scrapy 是一款強大且廣泛應用的 Python 爬蟲框架,它為爬蟲開發提供了高效、便捷的解決方案。

Scrapy 的架構猶如一個精密的機器,由多個核心組件協同工作。其中,引擎(Engine)是整個框架的核心樞紐,負責協調各個組件之間的通信和數據流動。它從調度器(Scheduler)獲取待爬取的 URL,將請求發送給下載器(Downloader),下載器從網絡上下載網頁內容後,再將響應返回給引擎,引擎又將響應傳遞給爬蟲(Spider)進行數據解析。而管道(Pipeline)則負責處理爬蟲提取的數據,進行數據的清洗、存儲等操作。調度器就像是一個智能的任務分配器,它維護著一個 URL 隊列,負責管理和調度待爬取的 URL,確保每個 URL 都能被合理地安排爬取順序,同時還能對重複的 URL 進行去重處理。

在使用 Scrapy 框架時,首先需要創建一個 Scrapy 項目。通過在命令行中輸入scrapy startproject 項目名稱,即可快速創建一個項目框架。例如,創建一個名為my_crawler的項目,命令如下:

scrapy startproject my\_crawler

進入項目目錄後,可以使用scrapy genspider 爬蟲名稱 目標域名命令創建一個爬蟲。假設要爬取example.com網站的數據,創建爬蟲的命令如下:

cd my\_crawler

scrapy genspider example\_spider example.com

在生成的爬蟲文件中,需要定義爬蟲的邏輯。例如,以下是一個簡單的爬蟲示例,用於爬取指定網頁上的標題信息:

import scrapy

class ExampleSpider(scrapy.Spider):

      name = "example\_spider"

      allowed\_domains = \["example.com"]

      start\_urls = \["https://example.com"]

      def parse(self, response):

          titles = response.css('title::text').extract()

          for title in titles:

              yield {'title': title}

在這個例子中,parse方法是爬蟲的核心邏輯部分,它使用 CSS 選擇器提取網頁中的標題信息,並通過yield將數據傳遞給管道進行後續處理。

6.2 PySpider 框架#

PySpider 是一個輕量級且功能強大的爬蟲框架,它具有獨特的特點和適用場景。

PySpider 的一大亮點是其提供了直觀易用的 WebUI 界面。通過這個界面,開發者可以方便地進行項目管理、任務監控以及結果查看。在 WebUI 中,你可以輕鬆地創建、編輯和啟動爬蟲任務,實時了解爬蟲的運行狀態,查看爬取到的數據結果,這大大提高了開發和調試的效率。

PySpider 支持多種數據存儲方式,包括 MySQL、MongoDB、Redis 等常見數據庫。這使得開發者可以根據項目的實際需求,靈活選擇最適合的數據存儲方案,方便後續的數據處理和分析。

它還具備強大的分佈式爬蟲能力。通過配置多個爬蟲節點,PySpider 可以實現高併發的爬取任務,顯著提高數據採集的速度和效率。這一特性使得它在處理大規模數據爬取任務時表現出色。

例如,使用 PySpider 爬取一個新聞網站的文章內容。首先,安裝 PySpider,可以通過pip install pyspider命令進行安裝。安裝完成後,啟動 PySpider 服務,輸入pyspider all命令。在瀏覽器中訪問http://localhost:5000,進入 PySpider 的 WebUI 界面。在 WebUI 中創建一個新的爬蟲項目,編寫如下爬蟲代碼:

from pyspider.libs.base\_handler import \*

class NewsSpider(BaseHandler):

      crawl\_config = {}

      @every(minutes=24 \* 60)

      def on\_start(self):

          self.crawl('https://news.example.com', callback=self.index\_page)

      def index\_page(self, response):

          for each in response.doc('a\[href^="http"]').items():

              self.crawl(each.attr.href, callback=self.detail\_page)

      def detail\_page(self, response):

          title = response.doc('title').text()

          content = response.doc('.article-content').text()

          return {'title': title, 'content': content}

在這個例子中,on_start方法定義了爬蟲的起始 URL,index_page方法用於解析列表頁,提取文章鏈接並交給detail_page方法進行詳情頁的解析,最終提取出文章的標題和內容。通過 PySpider 的 WebUI 界面,我們可以方便地啟動、監控和管理這個爬蟲任務。

七、實戰項目演練#

image

7.1 小型爬蟲項目#

為了讓大家更直觀地感受爬蟲的魅力,我們以爬取豆瓣電影 Top250 為例,展示一個完整的爬蟲實現過程。豆瓣電影 Top250 是電影愛好者們關注的熱門榜單,其中包含了豐富的電影信息。

首先,我們需要分析網頁結構。通過瀏覽器的開發者工具(如 Chrome 瀏覽器的 F12 快捷鍵),可以查看網頁的 HTML 源代碼,找到電影信息所在的標籤和屬性。例如,電影標題通常在<span class="title">標籤內,評分在<span class="rating_num">標籤內。

接下來,編寫爬蟲代碼。使用 Python 的requests庫和BeautifulSoup庫,代碼如下:

import requests

from bs4 import BeautifulSoup

import csv

def get\_movie\_info(url):

      headers = {

          "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

      }

      response = requests.get(url, headers = headers)

      if response.status\_code == 200:

          soup = BeautifulSoup(response.text, 'html.parser')

          movie\_list = soup.find\_all('div', class\_='item')

          for movie in movie\_list:

              title = movie.find('span', class\_='title').text

              rating = movie.find('span', class\_='rating\_num').text

              quote = movie.find('span', class\_='inq')

              quote = quote.text if quote else '無'

              yield {

                  'title': title,

                  'rating': rating,

                  'quote': quote

              }

      else:

          print(f"請求失敗,狀態碼: {response.status\_code}")

def save\_to\_csv(data, filename='douban\_movies.csv'):

      with open(filename, 'w', newline='', encoding='utf - 8') as csvfile:

          fieldnames = \['title', 'rating', 'quote']

          writer = csv.DictWriter(csvfile, fieldnames = fieldnames)

          writer.writeheader()

          for movie in data:

              writer.writerow(movie)

if \_\_name\_\_ == "\_\_main\_\_":

      base\_url = "https://movie.douban.com/top250?start={}\&filter="

      all\_movie\_info = \[]

      for start in range(0, 250, 25):

          url = base\_url.format(start)

          movie\_info = get\_movie\_info(url)

          all\_movie\_info.extend(movie\_info)

      save\_to\_csv(all\_movie\_info)

在這段代碼中,get_movie_info函數負責發送請求、解析網頁並提取電影的標題、評分和簡介信息。save_to_csv函數將提取到的數據保存為 CSV 文件。通過循環遍歷不同的頁碼,我們可以獲取到豆瓣電影 Top250 的所有信息。

7.2 大型綜合爬蟲項目#

現在,我們邁向一個更具挑戰性的任務 —— 爬取電商平台的商品信息,並實現數據持久化和分佈式爬蟲功能。以爬取某電商平台的手機商品信息為例,這一過程涉及多個複雜的環節。

首先,我們要解決反爬蟲問題。電商平台通常具有嚴格的反爬蟲機制,我們可以通過設置請求頭、使用代理 IP 等方式來偽裝請求。同時,為了實現數據持久化,我們選擇將數據存儲到 MySQL 數據庫中。以下是使用Scrapy框架實現的部分代碼示例:

import scrapy

import pymysql

class MobileSpider(scrapy.Spider):

      name = "mobile\_spider"

      allowed\_domains = \["example.com"]

      start\_urls = \["https://example.com/mobiles"]

      def parse(self, response):

          for mobile in response.css('.mobile-item'):

              item = {

                  'title': mobile.css('.title::text').get(),

                  'price': mobile.css('.price::text').get(),

                  'rating': mobile.css('.rating::text').get()

              }

              yield item

          next\_page = response.css('.next-page::attr(href)').get()

          if next\_page:

              yield response.follow(next\_page, self.parse)

class MySQLPipeline:

      def \_\_init\_\_(self):

          self.conn = pymysql.connect(

              host='localhost',

              user='root',

              password='password',

              db='ecommerce',

              charset='utf8'

          )

          self.cursor = self.conn.cursor()

      def process\_item(self, item, spider):

          sql = "INSERT INTO mobiles (title, price, rating) VALUES (%s, %s, %s)"

          values = (item\['title'], item\['price'], item\['rating'])

          self.cursor.execute(sql, values)

          self.conn.commit()

          return item

      def close\_spider(self, spider):

          self.cursor.close()

          self.conn.close()

在這段代碼中,MobileSpider類定義了爬蟲的邏輯,包括起始 URL、數據解析和分頁處理。MySQLPipeline類負責將爬取到的數據插入到 MySQL 數據庫的mobiles表中。

對於分佈式爬蟲,我們可以借助Scrapy - Redis框架來實現。Scrapy - Redis能夠將爬取任務分配到多個節點上並行執行,大大提高爬取效率。首先,需要安裝Scrapy - Redis庫,通過pip install scrapy - redis命令進行安裝。然後,在settings.py文件中進行如下配置:

# 啟用Redis調度存儲請求隊列

SCHEDULER = "scrapy\_redis.scheduler.Scheduler"

# 確保所有爬蟲共享相同的去重指紋

DUPEFILTER\_CLASS = "scrapy\_redis.dupefilter.RFPDupeFilter"

# Redis連接設置

REDIS\_HOST = 'localhost'

REDIS\_PORT = 6379

在爬蟲類中,繼承RedisSpider類,如下所示:

from scrapy\_redis.spiders import RedisSpider

class DistributedMobileSpider(RedisSpider):

      name = "distributed\_mobile\_spider"

      redis\_key = "mobile:start\_urls"

      def parse(self, response):

          # 解析邏輯與普通Spider類似

          pass

在這個配置中,redis_key指定了 Redis 中存儲起始 URL 的鍵。通過將起始 URL 放入 Redis 隊列中,不同的爬蟲節點可以從隊列中獲取任務並進行處理,從而實現分佈式爬取。

八、總結與展望#

image

在本次爬蟲之旅中,我們從基礎語法出發,逐步深入到爬蟲的核心原理、常用庫、進階技巧、框架應用以及實戰項目。通過學習,我們掌握了如何利用 Python 語言搭建爬蟲環境,使用各種庫和工具來發送 HTTP 請求、解析網頁數據、處理反爬蟲機制以及實現高效的數據採集。同時,我們還了解了不同爬蟲框架的特點和優勢,以及如何將其應用於實際項目中。

展望未來,爬蟲技術將隨著互聯網的發展而不斷演進。隨著大數據和人工智能技術的蓬勃發展,爬蟲技術有望在數據採集和分析方面發揮更為關鍵的作用。未來,爬蟲可能會更加智能化,能夠自動識別網頁結構的變化,靈活調整抓取策略,從而提高數據採集的準確性和效率。同時,在分佈式爬蟲領域,隨著技術的不斷完善,多節點協作的效率將進一步提升,能夠更快地處理大規模的數據爬取任務。此外,隨著數據安全和隱私保護意識的不斷增強,爬蟲技術也將更加注重合規性和安全性,確保在合法、安全的前提下進行數據採集。

爬蟲技術的發展前景廣闊,充滿了無限的可能性。希望大家在今後的學習和實踐中,能夠不斷探索和創新,充分發揮爬蟲技術的優勢,為各個領域的發展貢獻自己的力量。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。