用 Python 寫你的第一個爬蟲:小白也能輕松搞定數據抓取(超詳細包含最新所有Python爬蟲庫的教程)
摘要
本文是一篇面向爬蟲愛好者的超詳細 Python 爬蟲入門教程,涵蓋了從基礎到進階的所有關鍵技術點:使用 Requests 與 BeautifulSoup 實現靜態網頁數據抓取,運用 lxml、XPath、CSS 選擇器等高效解析技術,深入 Scrapy 框架搭建分布式爬蟲項目,掌握 Selenium 和 Playwright 瀏覽器自動化處理 JS 動態渲染,探索 aiohttp、HTTPX 異步爬蟲提升并發性能,并結合代理 IP 池、User-Agent 偽裝、驗證碼識別等反爬蟲策略應對電商數據抓取、新聞數據爬取、社交媒體采集等場景。快速上手大規模爬蟲項目,打造可擴展、高效穩定的數據抓取解決方案。
目錄
-
前言
-
爬蟲基礎知識
- 2.1 什么是爬蟲?
- 2.2 爬蟲的應用場景
- 2.3 爬蟲基本流程
- 2.4 需要注意的法律與倫理問題
-
開發環境準備
- 3.1 安裝 Python(建議 3.8 及以上)
- 3.2 創建虛擬環境并激活
- 3.3 常用開發工具推薦
-
基礎篇:用 Requests + BeautifulSoup 做簡單爬蟲
- 4.1 安裝必要庫
- 4.2 認識 HTTP 請求與響應
- 4.3 編寫第一個爬蟲:抓取網頁標題
- 4.4 解析HTML:BeautifulSoup 用法詳解
- 4.5 文件存儲:將抓到的數據保存為 CSV/JSON
- 4.6 常見反爬措施及應對策略
-
進階篇:更強大的解析工具
- 5.1 lxml (XPath)
- 5.2 parsel(Scrapy 內置的解析器)
- 5.3 PyQuery(類似 jQuery 的解析方式)
- 5.4 正則表達式在爬蟲中的應用
-
框架篇:Scrapy 全面入門
- 6.1 Scrapy 簡介
- 6.2 安裝與項目結構
- 6.3 編寫第一個 Scrapy 爬蟲 Spider
- 6.4 Item、Pipeline、Settings 詳解
- 6.5 Scrapy Shell 在線調試
- 6.6 分布式與多線程:Scrapy 爬蟲并發配置
- 6.7 Scrapy 中間件與擴展(Downloader Middleware、Downloader Handler)
-
動態內容爬取:Selenium 與 Playwright
- 7.1 為什么需要瀏覽器自動化?
- 7.2 Selenium 基礎用法
- 7.3 Playwright for Python(更快更輕量)
- 7.4 無頭瀏覽器(headless)模式及性能優化
- 7.5 結合 Selenium/Playwright 與 BeautifulSoup 解析
-
異步爬蟲:aiohttp + asyncio 與 HTTPX
- 8.1 同步 vs 異步:性能原理簡述
- 8.2 aiohttp 入門示例
- 8.3 使用 asyncio 協程池提高并發
- 8.4 HTTPX:Requests 的異步升級版
- 8.5 異步下使用解析庫示例(aiohttp + lxml)
-
數據存儲與去重
- 9.1 本地文件:CSV、JSON、SQLite
- 9.2 MySQL/PostgreSQL 等關系型數據庫
- 9.3 MongoDB 等 NoSQL 存儲
- 9.4 Redis 用作去重與短期緩存
- 9.5 去重策略:指紋、哈希、Bloom Filter
-
分布式爬蟲:Scrapy-Redis 與分布式調度
- 10.1 為什么要做分布式?
- 10.2 Scrapy-Redis 簡介與安裝
- 10.3 分布式去重隊列與調度
- 10.4 多機協作示例
-
常見反爬與反制策略
- 11.1 頻率限制與請求頭偽裝
- 11.2 登錄驗證與 Cookie 管理
- 11.3 驗證碼識別(簡單介紹)
- 11.4 代理 IP 池的搭建與旋轉
-
完整案例:爬取某新聞網站并存入數據庫
- 12.1 需求分析
- 12.2 使用 Scrapy + MySQL 完整實現
- 12.3 代碼詳解與常見 Q&A
-
Python 爬蟲相關的常用第三方庫一覽(截至 2024 年底)
- 13.1 基礎請求與解析
- 13.2 瀏覽器自動化
- 13.3 異步爬取
- 13.4 登錄模擬與驗證碼處理
- 13.5 反爬與代理
- 13.6 分布式調度
- 13.7 其它有用工具
-
附錄
- 14.1 常見報錯及解決方案
- 14.2 常用 HTTP 狀態碼速查
- 14.3 學習資源與進階指南
-
總結
1. 前言
在信息爆炸的時代,互聯網早已成為最豐富、最便捷的數據來源。從電商平臺的商品價格到新聞網站的最新動態,從社交媒體的熱門話題到招聘網站的職位信息,只要你想得到,幾乎都能通過爬蟲從網頁里“扒”出來。對于初學者而言,爬蟲其實并不神秘:只要理解 HTTP、HTML 及基本的 Python 編程,就能快速入門。本教程面向“零基礎”“小白”用戶,講解從最基本的抓取到進階框架、異步、分布式再到反爬策略,逐步深入,手把手指導你搭建完整爬蟲,并總結截至 2025 年最常用的 Python 爬蟲庫。
本教程特色
- 循序漸進:從最簡單的
requests + BeautifulSoup
開始,到 Scrapy、Selenium、Playwright、異步爬蟲,一步步掌握。 - 超詳細示例:每個工具/框架都配有完整可運行的示例代碼,你可以直接復制、運行、觀察。
- 最新庫盤點:整理并介紹了截至 2025 年所見的常用爬蟲生態中的主流庫,助你選對最合適的工具。
- 反爬與實戰:從簡單的 User-Agent 偽裝到代理 IP 池、驗證碼識別、分布式部署,多角度應對目標網站的各種反爬機制。
溫馨提示:
- 本教程示例均基于 Python 3.8+,強烈建議使用 Python 3.10 或更高版本來獲得更好的兼容性與性能。
- 爬取網站數據時,請務必遵守目標網站的
robots.txt
以及相關法律法規,避免給他人服務器帶來不必要的壓力。- 本文所列“最新庫”信息截止到 2024 年底,2025 年及以后的新庫、新特性請結合官方文檔或社區資源進行補充。
2. 爬蟲基礎知識
2.1 什么是爬蟲?
- 定義:爬蟲(Web Crawler,也稱 Spider、Bot)是一種通過程序自動訪問網頁,并將其中有用信息提取下來存儲的數據采集工具。
- 原理簡述:爬蟲首先向指定 URL 發起 HTTP 請求,獲取網頁源代碼(HTML、JSON、圖片等),再通過解析技術(如 XPath、CSS 選擇器、正則)從源碼中提取所需數據,最后將數據保存到文件或數據庫中。
2.2 爬蟲的應用場景
- 數據分析:電商價格監控、商品評論分析、競品調研。
- 輿情監控:社交媒體熱搜、論壇帖子、新聞資訊統計。
- 搜索引擎:Google、Bing、Baidu 等搜索引擎通過爬蟲定期抓取網頁進行索引。
- 招聘信息采集:自動抓取招聘網站的崗位、薪資、公司信息。
- 學術研究:論文元數據爬取、知識圖譜構建等。
- 內容聚合:如各類聚合網站把分散站點的文章集中到一個平臺。
2.3 爬蟲基本流程
- 確定目標 URL:明確要爬取的網頁地址,可能是靜態頁面,也可能是動態加載。
- 發送 HTTP 請求:通常使用
requests
、httpx
、aiohttp
等庫向目標 URL 發送 GET、POST 請求,并獲取響應。 - 解析響應內容:響應可能是 HTML、JSON、XML、圖片等,常用解析工具有 BeautifulSoup、lxml、parsel、PyQuery、正則表達式等。
- 提取數據:根據標簽名、屬性、XPath、CSS Selector 等定位到目標內容,抽取文本或屬性。
- 數據處理與存儲:將提取到的內容清洗、去重,然后保存到 CSV、JSON、SQLite、MySQL、MongoDB 等介質中。
- 翻頁/遞歸:如果需要多個頁面的數據,就要分析翻頁邏輯(URL 模板、Ajax 請求),循環執行請求與解析。
- 異常處理與反爬對策:設置代理、隨機 User-Agent、限速、IP 輪換,處理 HTTP 403、驗證碼、重定向等。
2.4 需要注意的法律與倫理問題
- 請求前務必查看目標站點的
robots.txt
(通常在https://example.com/robots.txt
),遵從抓取規則; - 有些站點禁止大量抓取、禁止商業用途,在爬取前請閱讀并遵守版權與隱私政策;
- 不要對目標站點造成過大壓力,建議設置合適的延時(
time.sleep
)、并發數限制; - 遵守爬蟲與爬取數據后續處理相關法律法規,切勿用于違法用途。
3. 開發環境準備
3.1 安裝 Python(建議 3.8 及以上)
-
Windows:
-
前往 https://www.python.org/downloads 下載對應 3.8+ 的安裝包,默認選中“Add Python 3.x to PATH”,點擊“Install Now”。
-
安裝完成后,打開命令行(Win + R → 輸入
cmd
→ 回車),執行:python --version pip --version
確認 Python 與 pip 已成功安裝。
-
-
macOS:
-
建議使用 Homebrew 安裝:
brew install python@3.10
-
安裝完成后,執行:
python3 --version pip3 --version
確認無誤后即可。
-
-
Linux (Ubuntu/Debian 系):
sudo apt update sudo apt install python3 python3-pip python3-venv -y
執行:
python3 --version pip3 --version
即可確認。
提示:如果你機器上同時安裝了 Python 2.x 和 Python 3.x,可能需要使用
python3
、pip3
來替代python
、pip
。
3.2 創建虛擬環境并激活
為了避免全局依賴沖突,強烈建議為每個爬蟲項目創建獨立的虛擬環境:
# 進入項目根目錄
mkdir my_spider && cd my_spider# 在項目目錄下創建虛擬環境(python3 -m venv venv 或 python -m venv venv)
python3 -m venv venv# 激活虛擬環境
# Windows:
venv\Scripts\activate# macOS/Linux:
source venv/bin/activate
激活后,終端左側會顯示 (venv)
,此時安裝的所有包都只作用于該環境。
3.3 常用開發工具推薦
-
IDE/編輯器:
- PyCharm Community / Professional:功能強大,集成測試、版本管理。
- VS Code:輕量且插件豐富,適合快速編輯。
- Sublime Text:輕量,啟動快;對于小腳本很方便。
-
調試工具:
- VS Code/PyCharm 自帶的調試器,可以單步、斷點調試。
- 對于命令行腳本,也可以使用
pdb
。
-
版本管理:
- Git + VS Code / PyCharm Git 插件,實現代碼托管與協作。
- 將項目托管到 GitHub/Gitee 等。
-
其他輔助:
- Postman / Insomnia:用于模擬 HTTP 請求、查看響應頭;
- Charles / Fiddler:抓包工具,可調試 AJAX 請求、Cookie、headers 等。
4. 基礎篇:用 Requests + BeautifulSoup 做簡單爬蟲
4.1 安裝必要庫
在虛擬環境中,執行:
pip install requests beautifulsoup4 lxml
requests
:Python 最常用的 HTTP 庫,用于發送 GET/POST 請求。beautifulsoup4
:常見的 HTML/XML 解析庫,入門簡單。lxml
:速度快、功能強大的解析器,供 BeautifulSoup 使用。
4.2 認識 HTTP 請求與響應
-
HTTP 請求:由方法(GET、POST、PUT 等)、URL、請求頭(Headers)、請求體(Body)等組成。
-
HTTP 響應:包含狀態碼(200、404、500 等)、響應頭、響應體(通常為 HTML、JSON、圖片、文件等)。
-
Requests 常用參數:
url
:請求地址。params
:URL 參數(字典/字符串)。headers
:自定義請求頭(例如 User-Agent、Referer、Cookie)。data
/json
:POST 請求時發送的表單或 JSON 數據。timeout
:超時時間(秒),防止請求一直卡住。proxies
:配置代理(詳見后文)。
示例:
import requestsurl = 'https://httpbin.org/get'
params = {'q': 'python 爬蟲', 'page': 1}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
}response = requests.get(url, params=params, headers=headers, timeout=10)
print(response.status_code) # 打印狀態碼,例如 200
print(response.encoding) # 編碼,例如 'utf-8'
print(response.text[:200]) # 前 200 字符
4.3 編寫第一個爬蟲:抓取網頁標題
下面以爬取「https://www.example.com」網頁標題為例,演示最簡單的流程:
# file: simple_spider.pyimport requests
from bs4 import BeautifulSoupdef fetch_title(url):try:# 1. 發送 GET 請求headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'}response = requests.get(url, headers=headers, timeout=10)response.raise_for_status() # 如果狀態碼不是 200,引發 HTTPError# 2. 設置正確的編碼response.encoding = response.apparent_encoding# 3. 解析 HTMLsoup = BeautifulSoup(response.text, 'lxml')# 4. 提取 <title> 標簽內容title_tag = soup.find('title')if title_tag:return title_tag.get_text().strip()else:return '未找到 title 標簽'except Exception as e:return f'抓取失敗:{e}'if __name__ == '__main__':url = 'https://www.example.com'title = fetch_title(url)print(f'網頁標題:{title}')
運行結果示例:
(venv) $ python simple_spider.py
網頁標題:Example Domain
4.4 解析HTML:BeautifulSoup 用法詳解
BeautifulSoup
庫使用簡單,常用方法如下:
-
創建對象
soup = BeautifulSoup(html_text, 'lxml') # 或 'html.parser'
-
查找單個節點
soup.find(tag_name, attrs={}, recursive=True, text=None, **kwargs)
- 示例:
soup.find('div', class_='content')
- 可以使用
attrs={'class': 'foo', 'id': 'bar'}
精確定位。
-
查找所有節點
soup.find_all(tag_name, attrs={}, limit=None, **kwargs)
- 示例:
soup.find_all('a', href=True)
返回所有帶href
的鏈接。
-
CSS 選擇器
soup.select('div.content > ul li a')
,返回列表。- 支持 id(
#id
)、class(.class
)、屬性([attr=value]
)等。
-
獲取屬性或文本
node.get('href')
:拿屬性值;node['href']
:同上,但如果屬性不存在會拋異常;node.get_text(strip=True)
:獲取節點文本,并去除前后空白;node.text
:獲取節點及子節點合并文本。
-
常用屬性
soup.title
/soup.title.string
/soup.title.text
soup.body
/soup.head
/soup.a
/soup.div
等快捷屬性。
-
示例:提取列表頁所有文章鏈接
html = response.text soup = BeautifulSoup(html, 'lxml') # 假設每篇文章鏈接都在 <h2 class="post-title"><a href="...">...</a></h2> for h2 in soup.find_all('h2', class_='post-title'):a_tag = h2.find('a')title = a_tag.get_text(strip=True)link = a_tag['href']print(title, link)
4.5 文件存儲:將抓到的數據保存為 CSV/JSON
-
CSV 格式
import csvdata = [{'title': '第一篇', 'url': 'https://...'},{'title': '第二篇', 'url': 'https://...'},# ... ]with open('result.csv', mode='w', newline='', encoding='utf-8-sig') as f:fieldnames = ['title', 'url']writer = csv.DictWriter(f, fieldnames=fieldnames)writer.writeheader()for item in data:writer.writerow(item)
encoding='utf-8-sig'
能兼容 Excel 打開時不出現亂碼。
-
JSON 格式
import jsondata = [{'title': '第一篇', 'url': 'https://...'},{'title': '第二篇', 'url': 'https://...'},# ... ]with open('result.json', 'w', encoding='utf-8') as f:json.dump(data, f, ensure_ascii=False, indent=4)
-
SQLite 存儲(適合小規模項目)
import sqlite3conn = sqlite3.connect('spider.db') cursor = conn.cursor() # 創建表(如果不存在) cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT,url TEXT UNIQUE); ''') # 插入數據 items = [('第一篇', 'https://...'),('第二篇', 'https://...'), ] for title, url in items:try:cursor.execute('INSERT INTO articles (title, url) VALUES (?, ?)', (title, url))except sqlite3.IntegrityError:pass # URL 已存在就跳過 conn.commit() conn.close()
4.6 常見反爬措施及應對策略
-
User-Agent 檢測
- 默認
requests
的 User-Agent 大多被識別為“爬蟲”,容易被屏蔽。 - 應用:在請求頭中隨機選用常見瀏覽器 User-Agent。
import randomUSER_AGENTS = ['Mozilla/5.0 ... Chrome/100.0.4896.127 ...','Mozilla/5.0 ... Firefox/110.0 ...','Mozilla/5.0 ... Safari/605.1.15 ...',# 更多可從網上獲取 ] headers = {'User-Agent': random.choice(USER_AGENTS)} response = requests.get(url, headers=headers)
- 默認
-
IP 限制
- 如果同一 IP 在短時間內發起大量請求,服務器可能會封禁或返回 403。
- 應對:使用代理池(詳見第 11 節),定期更換 IP。
-
Cookie 驗證
- 某些網站登錄后才能訪問完整內容,需要先模擬登錄獲取 Cookie,再在后續請求中帶上。
- 用
requests.Session()
管理會話,同一 Session 自動保存并發送 Cookie。
import requestssession = requests.Session() login_data = {'username': 'xxx', 'password': 'xxx'} session.post('https://example.com/login', data=login_data) # 登錄成功后,session 自動保存了 Cookie response = session.get('https://example.com/protected-page')
-
驗證碼
- 簡易驗證碼有時可通過 OCR 自動識別,但復雜圖片驗證碼需要專門打碼平臺或人工識別。
- 在入門階段,盡量選擇不需要驗證碼或搶先獲取 API。
-
AJAX / 動態渲染
- 如果頁面數據是通過 JavaScript 動態加載,直接用
requests
只能獲取靜態 HTML。 - 應用:可分析 AJAX 請求接口(Network 面板),直接請求接口返回的 JSON;或使用瀏覽器自動化工具(Selenium/Playwright)模擬瀏覽器渲染。
- 如果頁面數據是通過 JavaScript 動態加載,直接用
5. 進階篇:更強大的解析工具
雖然 BeautifulSoup 足以應付大部分新手場景,但當你遇到結構復雜、嵌套多、或需要批量高效提取時,下面這些工具會更適合。
5.1 lxml (XPath)
-
特點:基于 C 語言實現,解析速度快,支持標準的 XPath 查詢。
-
安裝:
pip install lxml
-
示例:
from lxml import etreehtml = '''<html><body><div class="post"><h2><a href="/p1">文章A</a></h2></div><div class="post"><h2><a href="/p2">文章B</a></h2></div> </body></html>'''# 1. 將文本轉換為 Element 對象 tree = etree.HTML(html)# 2. 使用 XPath 語法提取所有鏈接文本和 href titles = tree.xpath('//div[@class="post"]/h2/a/text()') links = tree.xpath('//div[@class="post"]/h2/a/@href')for t, l in zip(titles, links):print(t, l) # 輸出: # 文章A /p1 # 文章B /p2
-
常見 XPath 語法:
//tag[@attr="value"]
:查找所有符合條件的 tag。text()
:獲取文本節點;@href
:獲取屬性值;//div//a
:查找 div 下所有后代中的 a;//ul/li[1]
:查找第一個 li;contains(@class, "foo")
:class 中包含 foo 的元素。
5.2 parsel(Scrapy 內置的解析器)
-
特點:Scrapy 自帶的一套基于 Css/XPath 的快速解析工具,接口與 lxml 類似,但更貼合 Scrapy 的數據提取習慣。
-
安裝:
pip install parsel
-
示例:
from parsel import Selectorhtml = '''<ul><li class="item"><a href="/a1">Item1</a></li><li class="item"><a href="/a2">Item2</a></li> </ul>'''sel = Selector(text=html) # 使用 CSS 選擇器 for item in sel.css('li.item'):title = item.css('a::text').get()link = item.css('a::attr(href)').get()print(title, link) # 使用 XPath for item in sel.xpath('//li[@class="item"]'):title = item.xpath('./a/text()').get()link = item.xpath('./a/@href').get()print(title, link)
-
parsel.Selector
對象在 Scrapy 中經常用到,直接拿過來在項目外部也能用。
5.3 PyQuery(類似 jQuery 的解析方式)
-
特點:接口風格類似 jQuery,習慣了前端的同學會很快上手。
-
安裝:
pip install pyquery
-
示例:
from pyquery import PyQuery as pqhtml = '''<div id="posts"><h2><a href="/x1">新聞X1</a></h2><h2><a href="/x2">新聞X2</a></h2> </div>'''doc = pq(html) # 通過標簽/ID/css 選擇器定位 for item in doc('#posts h2'):# item 是 lxml 的 Element,需要再次包裝a = pq(item).find('a')title = a.text()url = a.attr('href')print(title, url)
-
PyQuery 內部使用 lxml 作為解析器,速度不遜于直接調用 lxml。
5.4 正則表達式在爬蟲中的應用
-
正則并不是萬能的 HTML 解析方案,但在提取簡單規則(如郵箱、電話號碼、特定模式字符串)時非常方便。
-
在爬蟲中,可先用 BeautifulSoup/lxml 找到相應的大塊內容,再對內容字符串用正則提取。
-
示例:
import re from bs4 import BeautifulSouphtml = '''<div class="info">聯系郵箱:abc@example.com聯系電話:123-4567-890 </div>'''soup = BeautifulSoup(html, 'lxml') info = soup.find('div', class_='info').get_text()# 匹配郵箱 email_pattern = r'[\w\.-]+@[\w\.-]+' emails = re.findall(email_pattern, info) print('郵箱:', emails)# 匹配電話號碼 phone_pattern = r'\d{3}-\d{4}-\d{3,4}' phones = re.findall(phone_pattern, info) print('電話:', phones)
6. 框架篇:Scrapy 全面入門
如果你想快速搭建一個可維護、可擴展的爬蟲項目,Scrapy 是 Python 爬蟲生態中最成熟、最流行的爬蟲框架之一。
6.1 Scrapy 簡介
-
Scrapy:一個專門為大規模網絡爬取與信息提取設計的開源框架,具有高性能、多并發、支持分布式、內置各種中間件與管道。
-
適用場景:
- 大規模爬取同類型大量網頁。
- 對頁面進行復雜數據清洗、去重、存儲。
- 需要高度定制化中間件或擴展時。
6.2 安裝與項目結構
-
安裝 Scrapy:
pip install scrapy
-
創建 Scrapy 項目:
scrapy startproject myproject
-
項目目錄結構(示例):
myproject/scrapy.cfg # 部署時使用的配置文件myproject/ # 項目 Python 模塊__init__.pyitems.py # 定義數據模型(Item)middlewares.py # 自定義中間件pipelines.py # 數據處理與存儲 Pipelinesettings.py # Scrapy 全局配置spiders/ # 各種爬蟲文件放在這里__init__.pyexample_spider.py
6.3 編寫第一個 Scrapy 爬蟲 Spider
假設我們要爬去 quotes.toscrape.com
網站上所有名言及作者:
-
在
myproject/spiders/
下新建quotes_spider.py
:import scrapy from myproject.items import MyprojectItemclass QuotesSpider(scrapy.Spider):name = 'quotes' # 爬蟲名,運行時指定allowed_domains = ['quotes.toscrape.com']start_urls = ['https://quotes.toscrape.com/']def parse(self, response):# 提取每個名言塊for quote in response.css('div.quote'):item = MyprojectItem()item['text'] = quote.css('span.text::text').get()item['author'] = quote.css('small.author::text').get()item['tags'] = quote.css('div.tags a.tag::text').getall()yield item# 翻頁:獲取下一頁鏈接并遞歸next_page = response.css('li.next a::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)
-
定義 Item 模型 (
myproject/items.py
):import scrapyclass MyprojectItem(scrapy.Item):text = scrapy.Field()author = scrapy.Field()tags = scrapy.Field()
-
配置數據存儲 Pipeline(可選存儲到 JSON/CSV/數據庫),如在
myproject/pipelines.py
:import jsonclass JsonWriterPipeline:def open_spider(self, spider):self.file = open('quotes.json', 'w', encoding='utf-8')self.file.write('[\n')def close_spider(self, spider):self.file.write('\n]')self.file.close()def process_item(self, item, spider):line = json.dumps(dict(item), ensure_ascii=False)self.file.write(line + ',\n')return item
并在
settings.py
中啟用:ITEM_PIPELINES = {'myproject.pipelines.JsonWriterPipeline': 300, }
-
運行爬蟲:
scrapy crawl quotes
運行后,會在項目根目錄生成
quotes.json
,其中包含抓取到的所有名言數據。
6.4 Item、Pipeline、Settings 詳解
- Items (
items.py
):定義要提取的數據結構與字段,相當于“數據模型”。 - Spiders (
spiders/xxx.py
):每個 spider 文件對應一個任務,可接收start_urls
、allowed_domains
、parse()
回調等。可自定義不同的回調函數來解析不同頁面。 - Pipelines (
pipelines.py
):處理從 Spider 返回的 Item,常見操作包括數據清洗(去重、格式化)、存儲(寫入 JSON/CSV、入庫)、下載附件等。 - Settings (
settings.py
):全局配置文件,包含并發數(CONCURRENT_REQUESTS
)、下載延時(DOWNLOAD_DELAY
)、中間件配置、管道配置、User-Agent 等。
常見 Settings 配置示例:
# settings.py(只列部分)
BOT_NAME = 'myproject'SPIDER_MODULES = ['myproject.spiders']
NEWSPIDER_MODULE = 'myproject.spiders'# 遵循 robots 協議
ROBOTSTXT_OBEY = True# 并發請求數(默認 16)
CONCURRENT_REQUESTS = 8# 下載延時(秒),防止對目標站造成過大壓力
DOWNLOAD_DELAY = 1# 配置 User-Agent
DEFAULT_REQUEST_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
}# 啟用 Pipeline
ITEM_PIPELINES = {'myproject.pipelines.JsonWriterPipeline': 300,
}# 啟用或禁用中間件、擴展、管道等
DOWNLOADER_MIDDLEWARES = {# 'myproject.middlewares.SomeDownloaderMiddleware': 543,
}# 日志等級
LOG_LEVEL = 'INFO'
6.5 Scrapy Shell 在線調試
-
Scrapy 提供了
scrapy shell <URL>
命令,可以快速測試 XPath、CSS 選擇器。scrapy shell 'https://quotes.toscrape.com/'
-
進入 shell 后,你可以執行:
>>> response.status 200 >>> response.css('div.quote span.text::text').getall() ['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', ...] >>> response.xpath('//div[@class="quote"]/span[@class="text"]/text()').getall()
-
Shell 模式下,你可以快速試錯、驗證提取邏輯,比寫完整 Spider 再跑要高效很多。
6.6 分布式與多線程:Scrapy 爬蟲并發配置
- 并發請求數:在
settings.py
中設置CONCURRENT_REQUESTS
(默認 16); - 單域名并發:
CONCURRENT_REQUESTS_PER_DOMAIN
(默認 8); - 單 IP 并發:
CONCURRENT_REQUESTS_PER_IP
; - 下載延時:
DOWNLOAD_DELAY
(默認 0); - 自動限速:
AUTOTHROTTLE_ENABLED = True
,配合AUTOTHROTTLE_START_DELAY
、AUTOTHROTTLE_MAX_DELAY
等。 - 并行請求:Scrapy 內部使用 Twisted 異步網絡庫實現高并發,單機即可輕松處理成千上萬請求。
6.7 Scrapy 中間件與擴展(Downloader Middleware、Downloader Handler)
-
Downloader Middleware:位于 Scrapy 引擎與下載器之間,可控制請求/響應,常用于:
- 動態設置 User-Agent、Proxy;
- 攔截并修改請求/響應頭;
- 處理重試(Retry)、重定向(Redirect)等。
-
示例:隨機 User-Agent Middleware
# myproject/middlewares.pyimport random from scrapy import signalsclass RandomUserAgentMiddleware:def __init__(self, user_agents):self.user_agents = user_agents@classmethoddef from_crawler(cls, crawler):return cls(user_agents=crawler.settings.get('USER_AGENTS_LIST'))def process_request(self, request, spider):ua = random.choice(self.user_agents)request.headers.setdefault('User-Agent', ua)
并在
settings.py
中配置:USER_AGENTS_LIST = ['Mozilla/5.0 ... Chrome/100.0 ...','Mozilla/5.0 ... Firefox/110.0 ...',# 更多 User-Agent ]DOWNLOADER_MIDDLEWARES = {'myproject.middlewares.RandomUserAgentMiddleware': 400,'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, }
-
Downloader Handler:更底層的接口,一般不常用,Scrapy 已提供
HttpDownloadHandler
、S3DownloadHandler
等。
7. 動態內容爬取:Selenium 與 Playwright
當目標網頁內容依賴 JavaScript 動態渲染時,單純用 requests
或 Scrapy 獲取到的 HTML 往往不包含最終可視化的數據。此時可以使用“瀏覽器自動化”工具,讓其像真實瀏覽器一樣加載頁面,再提取渲染后的內容。
7.1 為什么需要瀏覽器自動化?
-
許多現代網站(尤其是單頁應用 SPA)使用 React、Vue、Angular 等框架,通過 AJAX 或 API 獲取數據并在前端渲染,直接請求 URL 只能拿到空白或框架代碼。
-
瀏覽器自動化可以:
- 啟動一個真實或無頭瀏覽器實例;
- 訪問頁面,等待 JavaScript 執行完成;
- 拿到渲染完畢的 DOM,然后再用解析庫提取。
7.2 Selenium 基礎用法
-
安裝:
pip install selenium
-
下載 WebDriver(以 Chrome 為例):
- 前往 ChromeDriver 下載頁面 ,下載與本地 Chrome 版本相匹配的
chromedriver
。 - 將
chromedriver
放置在系統 PATH 下,或在代碼中指定路徑。
- 前往 ChromeDriver 下載頁面 ,下載與本地 Chrome 版本相匹配的
-
示例:抓取動態網頁內容
from selenium import webdriver from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options import time# 1. 配置 Chrome 選項 chrome_options = Options() chrome_options.add_argument('--headless') # 無界面模式 chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-gpu')# 2. 指定 chromedriver 路徑或直接放到 PATH 中 service = ChromeService(executable_path='path/to/chromedriver')# 3. 創建 WebDriver driver = webdriver.Chrome(service=service, options=chrome_options)try:# 4. 打開頁面driver.get('https://quotes.toscrape.com/js/') # 這是一個 JavaScript 渲染的示例# 5. 等待 JS 渲染,最簡單的方式:time.sleep(建議改用顯式/隱式等待)time.sleep(2)# 6. 提取渲染后的 HTMLhtml = driver.page_source# 7. 交給 BeautifulSoup 或 lxml 解析from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')for quote in soup.css('div.quote'):text = quote.find('span', class_='text').get_text()author = quote.find('small', class_='author').get_text()print(text, author) finally:driver.quit()
-
顯式等待與隱式等待
-
隱式等待:
driver.implicitly_wait(10)
,在尋找元素時最長等待 10 秒; -
顯式等待:使用
WebDriverWait
與ExpectedConditions
,例如:from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ECelement = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.quote')) )
-
7.3 Playwright for Python(更快更輕量)
-
Playwright:由微軟維護、繼承自 Puppeteer 的跨瀏覽器自動化庫,支持 Chromium、Firefox、WebKit,無需單獨下載 WebDriver。
-
優點:啟動速度快、API 簡潔、并發控制更靈活。
-
安裝:
pip install playwright # 安裝瀏覽器內核(只需第一次執行) playwright install
-
示例:抓取動態內容
import asyncio from playwright.async_api import async_playwright from bs4 import BeautifulSoupasync def main():async with async_playwright() as p:browser = await p.chromium.launch(headless=True)page = await browser.new_page()await page.goto('https://quotes.toscrape.com/js/')# 可選:等待某個元素加載完成await page.wait_for_selector('div.quote')content = await page.content() # 獲取渲染后的 HTMLawait browser.close()# 交給 BeautifulSoup 解析soup = BeautifulSoup(content, 'lxml')for quote in soup.select('div.quote'):text = quote.select_one('span.text').get_text()author = quote.select_one('small.author').get_text()print(text, author)if __name__ == '__main__':asyncio.run(main())
-
同步版 Playwright
如果你不想使用異步,也可以借助sync_api
:from playwright.sync_api import sync_playwright from bs4 import BeautifulSoupdef main():with sync_playwright() as p:browser = p.chromium.launch(headless=True)page = browser.new_page()page.goto('https://quotes.toscrape.com/js/')page.wait_for_selector('div.quote')html = page.content()browser.close()soup = BeautifulSoup(html, 'lxml')for quote in soup.select('div.quote'):text = quote.select_one('span.text').get_text()author = quote.select_one('small.author').get_text()print(text, author)if __name__ == '__main__':main()
7.4 無頭瀏覽器(headless)模式及性能優化
-
無頭模式:在 Linux 服務器等環境下,沒有圖形界面,需要
--headless
參數;在 macOS/Windows 上也可加速啟動。 -
資源限制:可以通過設置啟動參數降低資源占用,如:
- Chrome:
chrome_options.add_argument('--disable-gpu')
、--no-sandbox
、--disable-dev-shm-usage
; - Playwright:
browser = await p.chromium.launch(headless=True, args=['--disable-gpu', '--no-sandbox'])
。
- Chrome:
-
避免過度渲染:如果只想拿純數據,盡量通過分析接口(XHR 請求)直接調用后臺 API,不必啟動完整瀏覽器。
7.5 結合 Selenium/Playwright 與 BeautifulSoup 解析
一般流程:
- 用 Selenium/Playwright 拿到渲染后的
page_source
或content()
; - 用 BeautifulSoup/lxml 對 HTML 進行二次解析與提取。
示例綜合:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoupchrome_options = Options()
chrome_options.add_argument('--headless')
service = ChromeService('path/to/chromedriver')
driver = webdriver.Chrome(service=service, options=chrome_options)try:driver.get('https://example.com/dynamic-page')driver.implicitly_wait(5)html = driver.page_sourcesoup = BeautifulSoup(html, 'lxml')# 根據解析需求提取數據for item in soup.select('div.article'):title = item.select_one('h1').get_text()content = item.select_one('div.content').get_text(strip=True)print(title, content)
finally:driver.quit()
8. 異步爬蟲:aiohttp + asyncio 與 HTTPX
當面對上千個、甚至上萬個鏈接需要同時抓取時,同步阻塞式的 requests
就顯得效率低下。Python 原生的 asyncio
協程、aiohttp
庫或 httpx
異步模式可以極大提升并發性能。
8.1 同步 vs 異步:性能原理簡述
- 同步(Blocking):一次請求完畢后才開始下一次請求。
- 異步(Non-Blocking):發出請求后可立即切換到其他任務,網絡 I/O 等待期間不阻塞線程。
- 對于 I/O 密集型爬蟲,異步能顯著提高吞吐量。
8.2 aiohttp 入門示例
-
安裝:
pip install aiohttp
-
使用 asyncio + aiohttp 并發抓取
import asyncio import aiohttp from bs4 import BeautifulSoupasync def fetch(session, url):try:async with session.get(url, timeout=10) as response:text = await response.text()return textexcept Exception as e:print(f'抓取 {url} 失敗:{e}')return Noneasync def parse(html, url):if not html:returnsoup = BeautifulSoup(html, 'lxml')title = soup.find('title').get_text(strip=True) if soup.find('title') else 'N/A'print(f'URL: {url},Title: {title}')async def main(urls):# connector 限制最大并發數,防止打開過多 TCP 連接conn = aiohttp.TCPConnector(limit=50)async with aiohttp.ClientSession(connector=conn) as session:tasks = []for url in urls:task = asyncio.create_task(fetch(session, url))tasks.append(task)# gather 等待所有 fetch 完成htmls = await asyncio.gather(*tasks)# 逐一解析for html, url in zip(htmls, urls):await parse(html, url)if __name__ == '__main__':urls = [f'https://example.com/page/{i}' for i in range(1, 101)]asyncio.run(main(urls))
-
說明:
aiohttp.TCPConnector(limit=50)
將并發連接限制在 50,避免短時間打開過多連接被服務器封。asyncio.create_task
創建并發 Task,交由事件循環調度。await asyncio.gather(*)
等待所有任務完成。
8.3 使用 asyncio 協程池提高并發
如果需要對抓取和解析做更精細的并行控制,可使用 asyncio.Semaphore
或第三方協程池庫(如 aiomultiprocess、aiojobs)來控制并發數。
import asyncio
import aiohttp
from bs4 import BeautifulSoupsemaphore = asyncio.Semaphore(20) # 最多同時跑 20 個協程async def fetch_with_sem(session, url):async with semaphore:try:async with session.get(url, timeout=10) as resp:return await resp.text()except Exception as e:print(f'Error fetching {url}: {e}')return Noneasync def main(urls):async with aiohttp.ClientSession() as session:tasks = [asyncio.create_task(fetch_with_sem(session, url)) for url in urls]results = await asyncio.gather(*tasks)for html, url in zip(results, urls):if html:title = BeautifulSoup(html, 'lxml').find('title').get_text(strip=True)print(url, title)if __name__ == '__main__':sample_urls = [f'https://example.com/page/{i}' for i in range(1, 51)]asyncio.run(main(sample_urls))
8.4 HTTPX:Requests 的異步升級版
-
HTTPX:由 Encode 團隊開發,與
requests
API 十分相似,同時支持同步與異步模式。 -
安裝:
pip install httpx
-
示例:
import asyncio import httpx from bs4 import BeautifulSoupasync def fetch(client, url):try:resp = await client.get(url, timeout=10.0)resp.raise_for_status()return resp.textexcept Exception as e:print(f'Error {url}: {e}')return Noneasync def main(urls):async with httpx.AsyncClient(limits=httpx.Limits(max_connections=50)) as client:tasks = [asyncio.create_task(fetch(client, url)) for url in urls]for coro in asyncio.as_completed(tasks):html = await coroif html:title = BeautifulSoup(html, 'lxml').find('title').get_text(strip=True)print('Title:', title)if __name__ == '__main__':urls = [f'https://example.com/page/{i}' for i in range(1, 101)]asyncio.run(main(urls))
-
與
requests
兼容的 API(如.get()
、.post()
、.json()
、.text
等),極大降低了上手門檻。
8.5 異步下使用解析庫示例(aiohttp + lxml)
import asyncio
import aiohttp
from lxml import etreeasync def fetch_and_parse(session, url):try:async with session.get(url, timeout=10) as resp:text = await resp.text()tree = etree.HTML(text)# 提取第一條消息msg = tree.xpath('//div[@class="msg"]/text()')print(url, msg)except Exception as e:print(f'Error fetching {url}: {e}')async def main(urls):conn = aiohttp.TCPConnector(limit=30)async with aiohttp.ClientSession(connector=conn) as session:tasks = [fetch_and_parse(session, url) for url in urls]await asyncio.gather(*tasks)if __name__ == '__main__':url_list = [f'https://example.com/messages/{i}' for i in range(1, 51)]asyncio.run(main(url_list))
9. 數據存儲與去重
爬蟲的最終目的是獲取并存儲有價值的數據,因此選擇合適的存儲方式與去重機制至關重要。
9.1 本地文件:CSV、JSON、SQLite
-
CSV/JSON:
- 適合一次性、容量較小、對數據結構要求不高的場景。
- 直接用 Python 標準庫即可讀寫。
-
SQLite:
-
輕量級嵌入式數據庫,無需額外部署數據庫服務器。
-
適合中小規模項目,比如幾萬條數據。
-
示例:
import sqlite3conn = sqlite3.connect('data.db') cursor = conn.cursor() cursor.execute('CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, title TEXT, url TEXT UNIQUE)') data = [('標題1', 'https://a.com/1'), ('標題2', 'https://a.com/2')] for title, url in data:try:cursor.execute('INSERT INTO items (title, url) VALUES (?, ?)', (title, url))except sqlite3.IntegrityError:pass # 去重 conn.commit() conn.close()
-
9.2 MySQL/PostgreSQL 等關系型數據庫
-
優點:適合大規模數據存儲,支持 SQL 強大的查詢功能,能更好地做數據分析、統計。
-
安裝:先安裝對應數據庫服務器(MySQL、MariaDB、PostgreSQL),然后在 Python 中安裝驅動:
pip install pymysql # MySQL pip install psycopg2 # PostgreSQL
-
示例(MySQL):
import pymysqlconn = pymysql.connect(host='localhost', user='root', password='root', db='spider_db', charset='utf8mb4') cursor = conn.cursor() cursor.execute('''CREATE TABLE IF NOT EXISTS articles (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),url VARCHAR(255) UNIQUE) CHARACTER SET utf8mb4; ''') data = [('標題1', 'https://a.com/1'), ('標題2', 'https://a.com/2')] for title, url in data:try:cursor.execute('INSERT INTO articles (title, url) VALUES (%s, %s)', (title, url))except pymysql.err.IntegrityError:pass conn.commit() conn.close()
9.3 MongoDB 等 NoSQL 存儲
-
優點:文檔型數據庫,對半結構化 JSON 數據支持友好,可靈活存儲字段不同的條目。
-
安裝與驅動:
- 本地安裝 MongoDB 或使用云服務;
- Python 驅動:
pip install pymongo
。
-
示例:
from pymongo import MongoClientclient = MongoClient('mongodb://localhost:27017/') db = client['spider_db'] collection = db['articles'] # 插入或更新(去重依據:url) data = {'title': '標題1', 'url': 'https://a.com/1', 'tags': ['新聞', '推薦']} collection.update_one({'url': data['url']}, {'$set': data}, upsert=True)
9.4 Redis 用作去重與短期緩存
-
Redis:鍵值存儲,支持超高并發訪問,非常適合做指紋去重、短期緩存、隊列等。
-
常見策略:
- 布隆過濾器(Bloom Filter):當 URL 數量達到數百萬級別時,普通 Python 集合會占用大量內存,布隆過濾器用空間換時間,以極少內存判斷某個 URL 是否已爬取(有一定誤判率)。可以使用
pybloom-live
或直接在 Redis 中搭建 Bloom Filter(如 RedisBloom 模塊)。 - Redis Set:小規模去重可直接用 Redis set 存儲已爬 URL。
import redisr = redis.Redis(host='localhost', port=6379, db=0) url = 'https://example.com/page/1' # 嘗試添加到 set,返回 1 表示新添加,返回 0 表示已存在 if r.sadd('visited_urls', url):print('新 URL,可爬取') else:print('URL 已存在,跳過')
- 布隆過濾器(Bloom Filter):當 URL 數量達到數百萬級別時,普通 Python 集合會占用大量內存,布隆過濾器用空間換時間,以極少內存判斷某個 URL 是否已爬取(有一定誤判率)。可以使用
9.5 去重策略:指紋、哈希、Bloom Filter
-
指紋:通常對 URL 做標準化(去掉排序不同但內容相同的參數、多余的斜杠),然后對標準化后 URL 做哈希(如 MD5、SHA1),存到 Set 中對比。
-
Bloom Filter:一種以極少內存做到高效去重的概率算法,對大規模 URL 判斷去重十分劃算,但有極小誤判率(可能會把未訪問的 URL 誤判為已訪問)。
-
庫推薦:
pybloom-live
:純 Python 布隆過濾器庫;redis-py-bloom
或 Redis 官方RedisBloom
模塊(需 Redis 安裝相應擴展);- Scrapy 內置
scrapy.dupefilters.RFPDupeFilter
,默認用的是文件或 Redis 存儲的指紋去重。
10. 分布式爬蟲:Scrapy-Redis 與分布式調度
當單機爬蟲難以滿足高并發、大規模抓取時,就需要分布式爬蟲,將任務分布到多臺機器協同完成。Scrapy-Redis 是 Scrapy 官方推薦的分布式方案之一。
10.1 為什么要做分布式?
- 海量鏈接:需要抓取數百萬、上億條 URL 時,單機進程/線程或協程都難以在可接受時間內完成。
- 速度要求:需要更短時間內獲取全量數據,提高爬取速度。
- 容錯與擴展:分布式部署可實現節點增減、機器故障自愈等。
10.2 Scrapy-Redis 簡介與安裝
-
Scrapy-Redis:基于 Redis 存儲隊列與去重指紋,實現分布式調度、分布式去重、數據共享的 Scrapy 擴展。
-
安裝:
pip install scrapy-redis
10.3 分布式去重隊列與調度
-
在 Scrapy 項目中集成 Scrapy-Redis
-
修改
settings.py
:# settings.py # 使用 redis 作為調度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 每次爬蟲重啟時是否繼續未爬取完的爬取隊列 SCHEDULER_PERSIST = True # 使用 redis 去重(替換默認的 RFPDupeFilter) DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 指定 redis 鏈接地址 REDIS_URL = 'redis://:password@127.0.0.1:6379/0' # 將 item 存入 redis 由其他進程或管道處理 ITEM_PIPELINES = {'scrapy_redis.pipelines.RedisPipeline': 300 } # 指定用來存儲隊列的 redis key 前綴 REDIS_ITEMS_KEY = '%(spider)s:items' REDIS_START_URLS_KEY = '%(name)s:start_urls'
-
-
修改 Spider
- 繼承
scrapy_redis.spiders.RedisSpider
或RedisCrawlSpider
,將原本的start_urls
替換為從 Redis 隊列中獲取種子 URL。
# myproject/spiders/redis_quotes.pyfrom scrapy_redis.spiders import RedisSpider from myproject.items import MyprojectItemclass RedisQuotesSpider(RedisSpider):name = 'redis_quotes'# Redis 中存放 start_urls 的 keyredis_key = 'redis_quotes:start_urls'def parse(self, response):for quote in response.css('div.quote'):item = MyprojectItem()item['text'] = quote.css('span.text::text').get()item['author'] = quote.css('small.author::text').get()item['tags'] = quote.css('div.tags a.tag::text').getall()yield itemnext_page = response.css('li.next a::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)
- 繼承
-
將種子 URL 推入 Redis
-
在本地或遠程機器上,用
redis-cli
將種子 URL 推入列表:redis-cli lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
-
-
啟動分布式爬蟲
-
在多臺服務器或多終端分別啟動爬蟲:
scrapy crawl redis_quotes
-
所有實例會從同一個 Redis 隊列中獲取 URL,去重也基于 Redis,互不重復。
-
10.4 多機協作示例
-
部署多臺服務器(A、B、C),都能訪問同一個 Redis 實例。
-
在 A 機上運行:
redis-server # 啟動 Redis(可獨立部署)
-
在 A、B、C 機上,各自拉取完整的 Scrapy 項目代碼,并配置好
settings.py
中的REDIS_URL
。 -
在 A 機或任意一處,將種子 URL 塞入 Redis:
redis-cli -h A_ip -p 6379 lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
-
在 A、B、C 分別運行:
scrapy crawl redis_quotes
- 三臺機器會自動協調,每臺都從 Redis 隊列中取 URL,去重也由 Redis 統一維護。
-
數據收集:
- 爬取的 Item 通過
RedisPipeline
自動存入 Redis 列表(key:quotes:items
); - 之后可通過獨立腳本或 pipeline 再將數據持久化到數據庫/文件。
- 爬取的 Item 通過
11. 常見反爬與反制策略
11.1 頻率限制與請求頭偽裝
-
訪問頻率控制(限速)
-
對目標站設置隨機或固定延時:
import time, random time.sleep(random.uniform(1, 3)) # 隨機等待 1~3 秒
-
Scrapy 中使用
DOWNLOAD_DELAY
、AUTOTHROTTLE_ENABLED
等。
-
-
User-Agent 偽裝
- 通過隨機 User-Agent 模擬不同瀏覽器。
- 代碼示例見第 4.6 節。
-
Referer、Accept-Language、Accept-Encoding 等 Headers
-
模擬真實瀏覽器請求時攜帶的完整 Header:
headers = {'User-Agent': 'Mozilla/5.0 ...','Referer': 'https://example.com/','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8','Accept-Encoding': 'gzip, deflate, br',# 如有需要,可帶上 Cookie'Cookie': 'sessionid=xxx; other=yyy', } response = requests.get(url, headers=headers)
-
11.2 登錄驗證與 Cookie 管理
-
Session 對象:在
requests
中,使用requests.Session()
方便統一管理 Cookie。 -
模擬登錄流程:
- 獲取登錄頁
GET
請求,拿到隱藏的 token(如 CSRF); - 結合用戶名/密碼、token,
POST
到登錄接口; - 成功后,
session
內部有了 Cookie,后續使用同一 session 發起請求即可保持登錄狀態。
- 獲取登錄頁
-
帶 Cookie 抓取:
session = requests.Session() # 第一次請求,拿到 CSRF Token login_page = session.get('https://example.com/login') # 用 BeautifulSoup 解析隱藏 token from bs4 import BeautifulSoup soup = BeautifulSoup(login_page.text, 'lxml') token = soup.find('input', {'name': 'csrf_token'})['value']# 構造登錄表單 data = {'username': 'yourname','password': 'yourpwd','csrf_token': token } # 登錄 session.post('https://example.com/login', data=data, headers={'User-Agent': '...'}) # 登錄成功后用 session 繼續抓取需要登錄才能訪問的頁面 profile = session.get('https://example.com/profile') print(profile.text)
11.3 驗證碼識別(簡單介紹)
-
常見驗證碼類型:
- 驗證碼圖片(扭曲字母/數字);
- 滑動驗證碼(拼圖/拖動)
- 點選驗證碼(選特定圖像)
- 行為生物特征(人機驗證)
-
常用方案:
-
簡單 OCR 識別:用
pytesseract
對簡單數字/字母驗證碼進行識別,但對扭曲度高或干擾線多的驗證碼成功率不高。pip install pytesseract pillow
from PIL import Image import pytesseractimg = Image.open('captcha.png') text = pytesseract.image_to_string(img).strip() print('識別結果:', text)
-
打碼平臺/人工打碼:當驗證碼過于復雜時,可調用第三方打碼平臺 API(如超級鷹、打碼兔等),將圖片發送給平臺,由平臺返回識別結果;或者簡單地由人工識別。
-
繞過/獲取接口:很多網站的登錄并不真用驗證碼進行提交,而是在前端校驗。可以抓包找到真實的登錄接口,模擬接口請求,繞過驗證碼。
-
11.4 代理 IP 池的搭建與旋轉
-
為什么要用代理
- 同一 IP 短時間內請求次數過多容易被封禁;使用代理 IP 池可以不斷切換 IP,降低單 IP 請求頻率。
-
獲取代理
- 免費代理:網上公開的免費代理 IP,但一般不穩定、易失效。可用爬蟲定期從免費代理網站(如 xicidaili、kuaidaili)抓取可用代理,并驗證可用性。
- 付費代理:阿布云、快代理等付費代理服務,更穩定、更安全。
-
搭建本地簡單代理池示例(以免費代理為例,僅供學習)
import requests from lxml import etree import random import timedef fetch_free_proxies():url = 'https://www.kuaidaili.com/free/inha/1/'headers = {'User-Agent': 'Mozilla/5.0 ...'}resp = requests.get(url, headers=headers)tree = etree.HTML(resp.text)proxies = []for row in tree.xpath('//table//tr')[1:]:ip = row.xpath('./td[1]/text()')[0]port = row.xpath('./td[2]/text()')[0]proxy = f'http://{ip}:{port}'# 簡單校驗try:r = requests.get('https://httpbin.org/ip', proxies={'http': proxy, 'https': proxy}, timeout=3)if r.status_code == 200:proxies.append(proxy)except:continuereturn proxiesdef get_random_proxy(proxies):return random.choice(proxies) if proxies else Noneif __name__ == '__main__':proxy_list = fetch_free_proxies()print('可用代理:', proxy_list)# 實際爬蟲中使用示例:proxy = get_random_proxy(proxy_list)if proxy:resp = requests.get('https://example.com', proxies={'http': proxy, 'https': proxy}, timeout=10)print(resp.status_code)
-
在 Scrapy 中配置代理
-
簡單在
settings.py
中設置:# settings.py # 下載中間件(若自定義 proxy pool、user-agent,則參照上文中間件示例) DOWNLOADER_MIDDLEWARES = {'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,'myproject.middlewares.RandomProxyMiddleware': 100, } # 代理列表 PROXY_LIST = ['http://ip1:port1','http://ip2:port2',# ... ]
-
自定義
RandomProxyMiddleware
:# myproject/middlewares.pyimport randomclass RandomProxyMiddleware:def __init__(self, proxies):self.proxies = proxies@classmethoddef from_crawler(cls, crawler):return cls(proxies=crawler.settings.get('PROXY_LIST'))def process_request(self, request, spider):proxy = random.choice(self.proxies)request.meta['proxy'] = proxy
-
這樣 Scrapy 在每次請求時會隨機從
PROXY_LIST
中取一個代理。
-
12. 完整案例:爬取某新聞網站并存入數據庫
本節以“爬取某模擬新聞網站(示例:https://news.example.com
)的頭條新聞,并將標題、摘要、鏈接存入 MySQL 數據庫”為例,完整演示 Scrapy + MySQL 的使用。
12.1 需求分析
- 目標數據:新聞標題、摘要(簡介)、文章鏈接、發布時間。
- 爬取范圍:首頁頭條新聞(假設分頁結構或動態加載,可視情況調整)。
- 存儲方式:MySQL 數據庫,表名
headline_news
,字段:id, title, summary, url, pub_date
。 - 反爬策略:設置隨機 User-Agent、下載延時、簡單 IP 偽裝。
12.2 使用 Scrapy + MySQL 完整實現
-
創建 Scrapy 項目
scrapy startproject news_spider cd news_spider
-
安裝依賴
pip install scrapy pymysql
-
定義 Item (
news_spider/items.py
)import scrapyclass NewsSpiderItem(scrapy.Item):title = scrapy.Field()summary = scrapy.Field()url = scrapy.Field()pub_date = scrapy.Field()
-
設置 MySQL 配置 (
news_spider/settings.py
)# Database settings MYSQL_HOST = 'localhost' MYSQL_PORT = 3306 MYSQL_USER = 'root' MYSQL_PASSWORD = 'root' MYSQL_DB = 'news_db' MYSQL_CHARSET = 'utf8mb4'# Item Pipeline ITEM_PIPELINES = {'news_spider.pipelines.MySQLPipeline': 300, }# Download settings ROBOTSTXT_OBEY = True DOWNLOAD_DELAY = 1 CONCURRENT_REQUESTS = 8 USER_AGENTS_LIST = ['Mozilla/5.0 ... Chrome/100.0 ...','Mozilla/5.0 ... Firefox/110.0 ...',# 可自行補充 ] DOWNLOADER_MIDDLEWARES = {'news_spider.middlewares.RandomUserAgentMiddleware': 400,'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, }
-
自定義中間件:隨機 User-Agent (
news_spider/middlewares.py
)import randomclass RandomUserAgentMiddleware:def __init__(self, user_agents):self.user_agents = user_agents@classmethoddef from_crawler(cls, crawler):return cls(user_agents=crawler.settings.get('USER_AGENTS_LIST'))def process_request(self, request, spider):ua = random.choice(self.user_agents)request.headers.setdefault('User-Agent', ua)
-
MySQL Pipeline (
news_spider/pipelines.py
)import pymysql from pymysql.err import IntegrityErrorclass MySQLPipeline:def open_spider(self, spider):# 連接數據庫self.conn = pymysql.connect(host=spider.settings.get('MYSQL_HOST'),port=spider.settings.get('MYSQL_PORT'),user=spider.settings.get('MYSQL_USER'),password=spider.settings.get('MYSQL_PASSWORD'),db=spider.settings.get('MYSQL_DB'),charset=spider.settings.get('MYSQL_CHARSET'),cursorclass=pymysql.cursors.DictCursor)self.cursor = self.conn.cursor()# 創建表create_table_sql = """CREATE TABLE IF NOT EXISTS headline_news (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),summary TEXT,url VARCHAR(512) UNIQUE,pub_date DATETIME) CHARACTER SET utf8mb4;"""self.cursor.execute(create_table_sql)self.conn.commit()def close_spider(self, spider):self.cursor.close()self.conn.close()def process_item(self, item, spider):insert_sql = """INSERT INTO headline_news (title, summary, url, pub_date)VALUES (%s, %s, %s, %s)"""try:self.cursor.execute(insert_sql, (item.get('title'),item.get('summary'),item.get('url'),item.get('pub_date')))self.conn.commit()except IntegrityError:# URL 已存在則跳過passreturn item
-
編寫 Spider (
news_spider/spiders/news.py
)import scrapy from news_spider.items import NewsSpiderItemclass NewsSpider(scrapy.Spider):name = 'news'allowed_domains = ['news.example.com']start_urls = ['https://news.example.com/']def parse(self, response):# 假設首頁頭條新聞在 <div class="headline-list"> 下,每個新聞項 <div class="item">for news in response.css('div.headline-list div.item'):item = NewsSpiderItem()item['title'] = news.css('h2.title::text').get().strip()item['summary'] = news.css('p.summary::text').get().strip()item['url'] = response.urljoin(news.css('a::attr(href)').get())item['pub_date'] = news.css('span.pub-date::text').get().strip() # 需后續轉換為標準時間yield scrapy.Request(url=item['url'],callback=self.parse_detail,meta={'item': item})# 假設分頁結構:下一頁鏈接在 <a class="next-page" href="...">next_page = response.css('a.next-page::attr(href)').get()if next_page:yield response.follow(next_page, callback=self.parse)def parse_detail(self, response):item = response.meta['item']# 在詳情頁可提取更精確的發布時間pub_date = response.css('div.meta span.date::text').get().strip()item['pub_date'] = self.parse_date(pub_date)yield itemdef parse_date(self, date_str):# 假設 date_str 格式為 '2025-05-30 14:30:00'from datetime import datetimetry:dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')return dtexcept:return None
-
運行爬蟲
-
確保 MySQL 已創建數據庫
news_db
,用戶名、密碼正確; -
在項目根目錄執行:
scrapy crawl news
-
運行期間,日志會顯示抓取進度,成功后可在
headline_news
表中查看抓取結果:SELECT * FROM headline_news LIMIT 10;
-
12.3 代碼詳解與常見 Q&A
-
Q:為什么要在
parse
方法中發起新的 Request 到詳情頁?- 因為首頁展示的數據有限,有些字段(如精確發布時間、作者、正文)要到詳情頁才能拿到。
meta
參數可將部分已抓取的字段傳遞到下一個回調。
- 因為首頁展示的數據有限,有些字段(如精確發布時間、作者、正文)要到詳情頁才能拿到。
-
Q:如何將字符串
'2025-05-30 14:30:00'
轉為datetime
?- 使用 Python 標準庫
datetime.strptime
,傳入對應格式;若格式不一致,可先strip()
或正則提取。
- 使用 Python 標準庫
-
Q:如果目標網站有登錄或驗證碼怎么辦?
- 可在
start_requests
方法里模擬登錄(使用requests
+cookies
或 Selenium),登錄后獲取 Cookie,再將 Cookie 帶入 Scrapy 調用。
- 可在
-
Q:如何處理分頁數量巨大(上千頁)?
- 可分析 URL 規律(如
page=1,2,3...
),使用for page in range(1, 1001): yield scrapy.Request(...)
。注意限速與 IP 輪換,防止被封。
- 可分析 URL 規律(如
-
Q:為什么要隨機 User-Agent?
- 防止被網站識別為爬蟲。
-
Q:如何在 Scrapy 中使用代理?
- 參考第 11.4 節,在
DOWNLOADER_MIDDLEWARES
中配置自己的RandomProxyMiddleware
,或直接使用 Scrapy-Proxy-Pool 等庫。
- 參考第 11.4 節,在
13. Python 爬蟲相關的常用第三方庫一覽(截至 2025年6月)
以下對各類常用庫進行分類歸納,并附簡要說明與典型使用場景。
13.1 基礎請求與解析
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
requests | 同步 HTTP 請求,API 簡潔,生態成熟 | 絕大多數簡單爬蟲,表單提交、Cookie 支持 |
httpx | 支持同步 & 異步的 HTTP 客戶端,與 requests 兼容 | 需要異步或更多高級功能時的首選 |
aiohttp | 原生 asyncio 協程模式的 HTTP 客戶端 | 高并發抓取、異步爬蟲 |
urllib3 | 低級 HTTP 客戶端,requests 底層依賴 | 需要更底層的控制、定制化管理連接池時 |
BeautifulSoup (bs4) | HTML/XML 解析,入門簡單、靈活 | 初學者快速上手、解析復雜 HTML |
lxml | 基于 libxml2/libxslt 的高性能解析器,支持 XPath | 需要高性能、大量數據解析時,結合 XPath 提取 |
parsel | Scrapy 自帶的解析器,支持 CSS/XPath | Scrapy 項目中快捷解析、項目外獨立解析 |
PyQuery | 類似 jQuery 的解析 API,基于 lxml | 前端同學更習慣 CSS 選擇器,快速上手 |
re (正則) | Python 內置正則模塊,對結構簡單的文本進行模式匹配 | 提取郵箱、電話號碼、URL、數字等簡單模式 |
html5lib | 兼容性最強的解析器(支持容錯 HTML),速度相對較慢 | 需要解析結構嚴重不規范的 HTML 時 |
13.2 瀏覽器自動化
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
Selenium | 最成熟的瀏覽器自動化框架,支持 Chrome、Firefox、Edge 等 | 需模擬用戶操作 (點擊、滑動、表單提交)、抓取 JS 渲染內容 |
Playwright | 微軟出品,繼承 Puppeteer,API 簡潔,支持多瀏覽器 | 高性能 headless 模式,異步/同步模式都支持 |
Pyppeteer | Puppeteer 的 Python 移植版 | Node.js 用戶轉 Python 時快速上手 |
undetected-chromedriver | 對抗反爬,屏蔽 Selenium 特征 | 需要更強的逃避檢測能力,尤其面對高級反爬 |
Splash | 由 Scrapy-Splash 提供,基于 QtWebKit 的渲染服務 | Scrapy 與動態渲染結合,用于批量異步渲染 |
13.3 異步爬取
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
asyncio | Python 標準庫,提供事件循環與異步協程基礎 | 編寫異步爬蟲主框架 |
aiohttp | 基于 asyncio 的 HTTP 客戶端 | 高并發抓取、配合 BeautifulSoup/lxml 解析 |
httpx | 支持同步 & 異步,與 requests 接口兼容 | 希望無縫從 requests 切換到異步模式 |
trio | 另一個異步框架,示意圖結構友好,但生態相對較小 | 深度研究異步原理或希望新嘗試 |
curio | 純 Python 異步庫,強調簡潔 | 研究異步 I/O 原理的場景 |
aiofiles | 異步文件操作 | 異步模式下同時要讀寫大量文件 |
13.4 登錄模擬與驗證碼處理
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
requests + Session | 模擬登錄,自動管理 Cookie | 大部分需要登錄后抓取的場景 |
selenium | 瀏覽器自動化登錄,執行 JS,處理復雜登錄邏輯 | 登錄時有 JS 加密或動態 token |
Playwright | 與 Selenium 類似,但速度更快,接口更現代 | 更輕量級的瀏覽器自動化 |
pytesseract | OCR 識別圖片文字 | 簡單驗證碼識別 |
captcha_solver | 第三方打碼平臺 SDK | 需要調用付費打碼平臺處理驗證碼 |
twoCaptcha | 付費打碼平臺 Python 客戶端 | 需要可靠的驗證碼打碼服務 |
13.5 反爬與代理
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
fake-useragent | 隨機生成 User-Agent | 防止被識別為爬蟲 |
scrapy-fake-useragent | Scrapy 專用隨機 UA 插件 | Scrapy 項目中一鍵啟用隨機 UA |
requests-random-user-agent | 為 requests 提供隨機 UA 支持 | 輕松控制 requests 請求頭 |
scrapy-rotating-proxies | Scrapy 專用代理輪換中間件,用于自動切換代理池(付費或免費) | Scrapy 大規模抓取時避免單 IP 封禁 |
scrapy-proxies | 開源 Scrapy 代理中間件,可使用免費代理池 | 入門級 Scrapy 項目快速使用代理 |
proxylist2 | Python 包,從多個免費代理網站抓取代理 IP | 自動化維護免費代理列表 |
requests-redis-rotating-proxies | 結合 Redis 存儲代理列表,實現高可用代理池 | 中大型項目需集中管理代理 IP |
scrapy-user-agents | Scrapy 插件,內置常見 UA 列表 | 簡化 Scrapy 中的 UA 列表管理 |
cfscrape | 用于繞過 Cloudflare 簡易 JS 保護 | 某些站點需要繞過 Cloudflare 5 秒驗證頁面 |
13.6 分布式調度
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
scrapy-redis | Scrapy 分布式爬蟲擴展,統一 Redis 作為隊列與去重存儲 | 分布式 Scrapy 項目 |
scrapy-cluster | 基于 Kafka + Redis 的 Scrapy 分布式爬蟲系統 | 企業級分布式環境,需與消息隊列協同 |
Frigate | 高性能分布式爬蟲,結合 Redis + MongoDB | 大規模分布式爬取且需要與 NoSQL 存儲集成 |
PhantomJS + Splash | 無頭瀏覽器渲染服務,可與 Scrapy 搭配形成分布式渲染環境 | 需要大規模渲染 JS 頁面后再抓取 |
13.7 其它有用工具
庫 名 | 功能簡介 | 典型場景 |
---|---|---|
robotparser | Python 內置 urllib.robotparser ,解析 robots.txt | 爬蟲前先檢查 robots.txt |
tldextract | 提取域名、子域名、后綴 | 需要對 URL 做域名歸類或統計時 |
url-normalize | URL 規范化,去除重復查詢參數 | 爬蟲過程對 URL 進行標準化去重 |
logging | Python 標準庫,用于日志輸出 | 任何爬蟲項目都應進行日志記錄 |
fake_useragent | 動態獲取并生成隨機 UA | 避免 UA 列表過時 |
termcolor | 終端字符著色,調試輸出更直觀 | 爬蟲日志、調試時需要彩色提示 |
psutil | 系統資源監控,可查看 CPU、內存占用 | 長時間運行爬蟲時監控資源使用情況 |
schedule | 定時任務庫,可定時運行腳本 | 需要定時執行爬蟲任務 |
watchdog | 文件系統監控,當文件/目錄變化時觸發回調 | 實時監控爬取結果文件、觸發后續任務 |
說明:因篇幅所限,上表僅列出截至 2024 年底常用或較為穩定的 Python 爬蟲庫,后續可能有新庫或舊庫迭代,請根據實際需求及時查閱官方文檔或社區資源。
14. 附錄
14.1 常見報錯及解決方案
-
ModuleNotFoundError: No module named 'xxx'
- 原因:未安裝該包或安裝在全局而非虛擬環境中。
- 解決:確認當前虛擬環境是否已激活,并執行
pip install xxx
。
-
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]
-
原因:本機 CA 證書有問題,無法驗證 HTTPS。
-
解決:
- 升級
certifi
:pip install --upgrade certifi
; - 臨時忽略:
requests.get(url, verify=False)
(不推薦用于生產)。
- 升級
-
-
ValueError: too many values to unpack (expected 2)
在 XPath 返回多值時- 原因:使用
for x, y in tree.xpath(...)
,但 XPath 返回值數量與預期不符。 - 解決:檢查 XPath 語法,或者使用
zip()
將兩個列表匹配。
- 原因:使用
-
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH
- 原因:
chromedriver
未放在系統 PATH,或路徑不正確。 - 解決:下載與 Chrome 版本一致的
chromedriver
,并將其路徑添加到環境變量,或者在代碼中指定executable_path
。
- 原因:
-
pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
- 原因:MySQL 用戶名/密碼、權限或 MySQL 服務未啟動。
- 解決:檢查用戶名、密碼是否正確,MySQL 服務是否運行,數據庫名稱是否存在。
-
TimeoutError
或asyncio.exceptions.TimeoutError
- 原因:網絡慢或被目標站點限制。
- 解決:加大
timeout
參數,降低并發數,適當設置代理。
-
UnicodeEncodeError/UnicodeDecodeError
- 原因:處理的文本編碼與 Python 默認編碼不一致。
- 解決:明確指定
response.encoding = 'utf-8'
,或者在讀寫文件時加encoding='utf-8'
。
14.2 常用 HTTP 狀態碼速查
狀態碼 | 含義 |
---|---|
200 | OK,請求成功 |
301 | 永久重定向 |
302 | 臨時重定向 |
400 | Bad Request,請求報文語法錯誤 |
401 | Unauthorized,需要身份驗證 |
403 | Forbidden,服務器拒絕訪問(常見反爬屏蔽碼) |
404 | Not Found,資源不存在 |
405 | Method Not Allowed,請求方法被禁止 |
408 | Request Timeout,服務器等待客戶端發送請求超時 |
429 | Too Many Requests,客戶端請求頻率過高 |
500 | Internal Server Error,服務器內部錯誤 |
502 | Bad Gateway,服務器作為網關或代理時收到上游服務器無效響應 |
503 | Service Unavailable,服務器暫時無法處理請求,常見于流量過大被限流 |
14.3 學習資源與進階指南
-
官方文檔
- Requests:https://docs.python-requests.org/
- BeautifulSoup:http://beautifulsoup.readthedocs.io/
- Scrapy:https://docs.scrapy.org/
- Selenium:https://www.selenium.dev/documentation/
- Playwright:https://playwright.dev/python/
- aiohttp:https://docs.aiohttp.org/
- httpx:https://www.python-httpx.org/
-
推薦書籍
- 《Python網絡數據采集(第二版)》—— Ryan Mitchell
- 《深入Python爬蟲框架 Scrapy》—— 黃今
- 《Python3網絡爬蟲開發實戰》—— 石剛
-
課程與視頻
- B 站、YouTube 上均有優質 Python 爬蟲視頻教程(可搜索“Python 爬蟲 零基礎”、“Scrapy 教程”等)。
- Coursera/慕課網上的 Python 爬蟲進階課程。
-
社區資源
- Stack Overflow:https://stackoverflow.com/(遇到報錯可搜索)
- SegmentFault:https://segmentfault.com/(國內開發者社區)
- GitHub Trending:搜索開源爬蟲項目,學習最佳實踐。
15. 總結
本教程從最基礎的 requests + BeautifulSoup
,到 Scrapy 框架、瀏覽器自動化、異步爬蟲、分布式爬蟲,系統梳理了 Python 爬蟲的常見技術與實踐要點,并盤點了截至 2024 年底的主流庫與工具。對于初學者而言,掌握以下幾個關鍵點即可快速上手:
- 理解 HTTP 基礎:會構造 GET/POST 請求、分析響應;
- 掌握 HTML 解析:熟悉 BeautifulSoup、lxml(XPath/CSS Selector);
- 嘗試 Scrapy:學會搭建 Scrapy 項目、編寫 Spider、Pipeline、Settings,并用 Scrapy Shell 調試;
- 應對動態頁面:熟練使用 Selenium 或 Playwright 抓取 JS 渲染內容,并結合常規解析方法提取數據;
- 探索異步爬蟲:理解協程原理,用 aiohttp、httpx 提升并發性能;
- 數據存儲與去重:掌握 CSV/JSON/SQLite/MySQL/MongoDB 的使用,并做好 URL 去重(集合、Redis、Bloom Filter);
- 反爬與反制:設置 User-Agent、Referer、下載延時、代理 IP 池等,了解驗證碼處理思路;
- 分布式爬蟲:學習 Scrapy-Redis,將任務分配到多臺機器,提高抓取效率。
最后,爬蟲技術更新迅速,截止到本教程編寫時(2024 年底)的主流庫可能會隨著技術迭代、站點反爬升級而發生變化。建議你在入門后,積極關注各大 Python 社區、GitHub Trending 以及官方文檔,及時跟進新特性、新庫、新思路,不斷優化自己的爬蟲方案。祝你能在數據抓取的道路上越走越遠,愉快地玩轉 Python 爬蟲世界!
創作時間:2025 年 6 月 1 日