用 Python 寫你的第一個爬蟲:小白也能輕松搞定數據抓取(超詳細包含最新所有Python爬蟲庫的教程)

用 Python 寫你的第一個爬蟲:小白也能輕松搞定數據抓取(超詳細包含最新所有Python爬蟲庫的教程)

摘要

本文是一篇面向爬蟲愛好者的超詳細 Python 爬蟲入門教程,涵蓋了從基礎到進階的所有關鍵技術點:使用 Requests 與 BeautifulSoup 實現靜態網頁數據抓取,運用 lxml、XPath、CSS 選擇器等高效解析技術,深入 Scrapy 框架搭建分布式爬蟲項目,掌握 Selenium 和 Playwright 瀏覽器自動化處理 JS 動態渲染,探索 aiohttp、HTTPX 異步爬蟲提升并發性能,并結合代理 IP 池、User-Agent 偽裝、驗證碼識別等反爬蟲策略應對電商數據抓取、新聞數據爬取、社交媒體采集等場景。快速上手大規模爬蟲項目,打造可擴展、高效穩定的數據抓取解決方案。


用 Python 寫你的第一個爬蟲:小白也能輕松搞定數據抓取(超詳細包含最新所有Python爬蟲庫的教程)

目錄

  1. 前言

  2. 爬蟲基礎知識

    • 2.1 什么是爬蟲?
    • 2.2 爬蟲的應用場景
    • 2.3 爬蟲基本流程
    • 2.4 需要注意的法律與倫理問題
  3. 開發環境準備

    • 3.1 安裝 Python(建議 3.8 及以上)
    • 3.2 創建虛擬環境并激活
    • 3.3 常用開發工具推薦
  4. 基礎篇:用 Requests + BeautifulSoup 做簡單爬蟲

    • 4.1 安裝必要庫
    • 4.2 認識 HTTP 請求與響應
    • 4.3 編寫第一個爬蟲:抓取網頁標題
    • 4.4 解析HTML:BeautifulSoup 用法詳解
    • 4.5 文件存儲:將抓到的數據保存為 CSV/JSON
    • 4.6 常見反爬措施及應對策略
  5. 進階篇:更強大的解析工具

    • 5.1 lxml (XPath)
    • 5.2 parsel(Scrapy 內置的解析器)
    • 5.3 PyQuery(類似 jQuery 的解析方式)
    • 5.4 正則表達式在爬蟲中的應用
  6. 框架篇: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)
  7. 動態內容爬取:Selenium 與 Playwright

    • 7.1 為什么需要瀏覽器自動化?
    • 7.2 Selenium 基礎用法
    • 7.3 Playwright for Python(更快更輕量)
    • 7.4 無頭瀏覽器(headless)模式及性能優化
    • 7.5 結合 Selenium/Playwright 與 BeautifulSoup 解析
  8. 異步爬蟲:aiohttp + asyncio 與 HTTPX

    • 8.1 同步 vs 異步:性能原理簡述
    • 8.2 aiohttp 入門示例
    • 8.3 使用 asyncio 協程池提高并發
    • 8.4 HTTPX:Requests 的異步升級版
    • 8.5 異步下使用解析庫示例(aiohttp + lxml)
  9. 數據存儲與去重

    • 9.1 本地文件:CSV、JSON、SQLite
    • 9.2 MySQL/PostgreSQL 等關系型數據庫
    • 9.3 MongoDB 等 NoSQL 存儲
    • 9.4 Redis 用作去重與短期緩存
    • 9.5 去重策略:指紋、哈希、Bloom Filter
  10. 分布式爬蟲:Scrapy-Redis 與分布式調度

    • 10.1 為什么要做分布式?
    • 10.2 Scrapy-Redis 簡介與安裝
    • 10.3 分布式去重隊列與調度
    • 10.4 多機協作示例
  11. 常見反爬與反制策略

    • 11.1 頻率限制與請求頭偽裝
    • 11.2 登錄驗證與 Cookie 管理
    • 11.3 驗證碼識別(簡單介紹)
    • 11.4 代理 IP 池的搭建與旋轉
  12. 完整案例:爬取某新聞網站并存入數據庫

    • 12.1 需求分析
    • 12.2 使用 Scrapy + MySQL 完整實現
    • 12.3 代碼詳解與常見 Q&A
  13. Python 爬蟲相關的常用第三方庫一覽(截至 2024 年底)

    • 13.1 基礎請求與解析
    • 13.2 瀏覽器自動化
    • 13.3 異步爬取
    • 13.4 登錄模擬與驗證碼處理
    • 13.5 反爬與代理
    • 13.6 分布式調度
    • 13.7 其它有用工具
  14. 附錄

    • 14.1 常見報錯及解決方案
    • 14.2 常用 HTTP 狀態碼速查
    • 14.3 學習資源與進階指南
  15. 總結


1. 前言

在信息爆炸的時代,互聯網早已成為最豐富、最便捷的數據來源。從電商平臺的商品價格到新聞網站的最新動態,從社交媒體的熱門話題到招聘網站的職位信息,只要你想得到,幾乎都能通過爬蟲從網頁里“扒”出來。對于初學者而言,爬蟲其實并不神秘:只要理解 HTTP、HTML 及基本的 Python 編程,就能快速入門。本教程面向“零基礎”“小白”用戶,講解從最基本的抓取到進階框架、異步、分布式再到反爬策略,逐步深入,手把手指導你搭建完整爬蟲,并總結截至 2025 年最常用的 Python 爬蟲庫。

本教程特色

  • 循序漸進:從最簡單的 requests + BeautifulSoup 開始,到 Scrapy、Selenium、Playwright、異步爬蟲,一步步掌握。
  • 超詳細示例:每個工具/框架都配有完整可運行的示例代碼,你可以直接復制、運行、觀察。
  • 最新庫盤點:整理并介紹了截至 2025 年所見的常用爬蟲生態中的主流庫,助你選對最合適的工具。
  • 反爬與實戰:從簡單的 User-Agent 偽裝到代理 IP 池、驗證碼識別、分布式部署,多角度應對目標網站的各種反爬機制。

溫馨提示

  1. 本教程示例均基于 Python 3.8+,強烈建議使用 Python 3.10 或更高版本來獲得更好的兼容性與性能。
  2. 爬取網站數據時,請務必遵守目標網站的 robots.txt 以及相關法律法規,避免給他人服務器帶來不必要的壓力。
  3. 本文所列“最新庫”信息截止到 2024 年底,2025 年及以后的新庫、新特性請結合官方文檔或社區資源進行補充。

2. 爬蟲基礎知識

2.1 什么是爬蟲?

  • 定義:爬蟲(Web Crawler,也稱 Spider、Bot)是一種通過程序自動訪問網頁,并將其中有用信息提取下來存儲的數據采集工具。
  • 原理簡述:爬蟲首先向指定 URL 發起 HTTP 請求,獲取網頁源代碼(HTML、JSON、圖片等),再通過解析技術(如 XPath、CSS 選擇器、正則)從源碼中提取所需數據,最后將數據保存到文件或數據庫中。

2.2 爬蟲的應用場景

  1. 數據分析:電商價格監控、商品評論分析、競品調研。
  2. 輿情監控:社交媒體熱搜、論壇帖子、新聞資訊統計。
  3. 搜索引擎:Google、Bing、Baidu 等搜索引擎通過爬蟲定期抓取網頁進行索引。
  4. 招聘信息采集:自動抓取招聘網站的崗位、薪資、公司信息。
  5. 學術研究:論文元數據爬取、知識圖譜構建等。
  6. 內容聚合:如各類聚合網站把分散站點的文章集中到一個平臺。

2.3 爬蟲基本流程

  1. 確定目標 URL:明確要爬取的網頁地址,可能是靜態頁面,也可能是動態加載。
  2. 發送 HTTP 請求:通常使用 requestshttpxaiohttp 等庫向目標 URL 發送 GET、POST 請求,并獲取響應。
  3. 解析響應內容:響應可能是 HTML、JSON、XML、圖片等,常用解析工具有 BeautifulSoup、lxml、parsel、PyQuery、正則表達式等。
  4. 提取數據:根據標簽名、屬性、XPath、CSS Selector 等定位到目標內容,抽取文本或屬性。
  5. 數據處理與存儲:將提取到的內容清洗、去重,然后保存到 CSV、JSON、SQLite、MySQL、MongoDB 等介質中。
  6. 翻頁/遞歸:如果需要多個頁面的數據,就要分析翻頁邏輯(URL 模板、Ajax 請求),循環執行請求與解析。
  7. 異常處理與反爬對策:設置代理、隨機 User-Agent、限速、IP 輪換,處理 HTTP 403、驗證碼、重定向等。

2.4 需要注意的法律與倫理問題

  • 請求前務必查看目標站點的 robots.txt(通常在 https://example.com/robots.txt),遵從抓取規則;
  • 有些站點禁止大量抓取、禁止商業用途,在爬取前請閱讀并遵守版權與隱私政策;
  • 不要對目標站點造成過大壓力,建議設置合適的延時(time.sleep)、并發數限制;
  • 遵守爬蟲與爬取數據后續處理相關法律法規,切勿用于違法用途。

3. 開發環境準備

3.1 安裝 Python(建議 3.8 及以上)

  1. 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 已成功安裝。

  2. macOS

    • 建議使用 Homebrew 安裝:

      brew install python@3.10
      
    • 安裝完成后,執行:

      python3 --version
      pip3 --version
      

      確認無誤后即可。

  3. 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,可能需要使用 python3pip3 來替代 pythonpip

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 庫使用簡單,常用方法如下:

  1. 創建對象

    soup = BeautifulSoup(html_text, 'lxml')  # 或 'html.parser'
    
  2. 查找單個節點

    • soup.find(tag_name, attrs={}, recursive=True, text=None, **kwargs)
    • 示例:soup.find('div', class_='content')
    • 可以使用 attrs={'class': 'foo', 'id': 'bar'} 精確定位。
  3. 查找所有節點

    • soup.find_all(tag_name, attrs={}, limit=None, **kwargs)
    • 示例:soup.find_all('a', href=True) 返回所有帶 href 的鏈接。
  4. CSS 選擇器

    • soup.select('div.content > ul li a'),返回列表。
    • 支持 id(#id)、class(.class)、屬性([attr=value])等。
  5. 獲取屬性或文本

    • node.get('href'):拿屬性值;
    • node['href']:同上,但如果屬性不存在會拋異常;
    • node.get_text(strip=True):獲取節點文本,并去除前后空白;
    • node.text:獲取節點及子節點合并文本。
  6. 常用屬性

    • soup.title / soup.title.string / soup.title.text
    • soup.body / soup.head / soup.a / soup.div 等快捷屬性。
  7. 示例:提取列表頁所有文章鏈接

    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

  1. 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 打開時不出現亂碼。
  2. 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)
    
  3. 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 常見反爬措施及應對策略

  1. 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)
    
  2. IP 限制

    • 如果同一 IP 在短時間內發起大量請求,服務器可能會封禁或返回 403。
    • 應對:使用代理池(詳見第 11 節),定期更換 IP。
  3. 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')
    
  4. 驗證碼

    • 簡易驗證碼有時可通過 OCR 自動識別,但復雜圖片驗證碼需要專門打碼平臺或人工識別。
    • 在入門階段,盡量選擇不需要驗證碼或搶先獲取 API。
  5. AJAX / 動態渲染

    • 如果頁面數據是通過 JavaScript 動態加載,直接用 requests 只能獲取靜態 HTML。
    • 應用:可分析 AJAX 請求接口(Network 面板),直接請求接口返回的 JSON;或使用瀏覽器自動化工具(Selenium/Playwright)模擬瀏覽器渲染。

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 安裝與項目結構

  1. 安裝 Scrapy:

    pip install scrapy
    
  2. 創建 Scrapy 項目:

    scrapy startproject myproject
    
  3. 項目目錄結構(示例):

    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 網站上所有名言及作者:

  1. 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)
    
  2. 定義 Item 模型 (myproject/items.py):

    import scrapyclass MyprojectItem(scrapy.Item):text = scrapy.Field()author = scrapy.Field()tags = scrapy.Field()
    
  3. 配置數據存儲 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,
    }
    
  4. 運行爬蟲:

    scrapy crawl quotes
    

    運行后,會在項目根目錄生成 quotes.json,其中包含抓取到的所有名言數據。

6.4 Item、Pipeline、Settings 詳解

  • Items (items.py):定義要提取的數據結構與字段,相當于“數據模型”。
  • Spiders (spiders/xxx.py):每個 spider 文件對應一個任務,可接收 start_urlsallowed_domainsparse() 回調等。可自定義不同的回調函數來解析不同頁面。
  • 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_DELAYAUTOTHROTTLE_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 已提供 HttpDownloadHandlerS3DownloadHandler 等。


7. 動態內容爬取:Selenium 與 Playwright

當目標網頁內容依賴 JavaScript 動態渲染時,單純用 requests 或 Scrapy 獲取到的 HTML 往往不包含最終可視化的數據。此時可以使用“瀏覽器自動化”工具,讓其像真實瀏覽器一樣加載頁面,再提取渲染后的內容。

7.1 為什么需要瀏覽器自動化?

  • 許多現代網站(尤其是單頁應用 SPA)使用 React、Vue、Angular 等框架,通過 AJAX 或 API 獲取數據并在前端渲染,直接請求 URL 只能拿到空白或框架代碼。

  • 瀏覽器自動化可以:

    1. 啟動一個真實或無頭瀏覽器實例;
    2. 訪問頁面,等待 JavaScript 執行完成;
    3. 拿到渲染完畢的 DOM,然后再用解析庫提取。

7.2 Selenium 基礎用法

  1. 安裝

    pip install selenium
    
  2. 下載 WebDriver(以 Chrome 為例):

    • 前往 ChromeDriver 下載頁面 ,下載與本地 Chrome 版本相匹配的 chromedriver
    • chromedriver 放置在系統 PATH 下,或在代碼中指定路徑。
  3. 示例:抓取動態網頁內容

    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()
    
  4. 顯式等待與隱式等待

    • 隱式等待driver.implicitly_wait(10),在尋找元素時最長等待 10 秒;

    • 顯式等待:使用 WebDriverWaitExpectedConditions,例如:

      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'])
  • 避免過度渲染:如果只想拿純數據,盡量通過分析接口(XHR 請求)直接調用后臺 API,不必啟動完整瀏覽器。

7.5 結合 Selenium/Playwright 與 BeautifulSoup 解析

一般流程:

  1. 用 Selenium/Playwright 拿到渲染后的 page_sourcecontent()
  2. 用 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 入門示例

  1. 安裝

    pip install aiohttp
    
  2. 使用 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))
    
  3. 說明

    • 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

  1. CSV/JSON

    • 適合一次性、容量較小、對數據結構要求不高的場景。
    • 直接用 Python 標準庫即可讀寫。
  2. 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:鍵值存儲,支持超高并發訪問,非常適合做指紋去重、短期緩存、隊列等。

  • 常見策略

    1. 布隆過濾器(Bloom Filter):當 URL 數量達到數百萬級別時,普通 Python 集合會占用大量內存,布隆過濾器用空間換時間,以極少內存判斷某個 URL 是否已爬取(有一定誤判率)。可以使用 pybloom-live 或直接在 Redis 中搭建 Bloom Filter(如 RedisBloom 模塊)。
    2. 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 已存在,跳過')
    

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 分布式去重隊列與調度

  1. 在 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'
      
  2. 修改 Spider

    • 繼承 scrapy_redis.spiders.RedisSpiderRedisCrawlSpider,將原本的 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)
    
  3. 將種子 URL 推入 Redis

    • 在本地或遠程機器上,用 redis-cli 將種子 URL 推入列表:

      redis-cli
      lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
      
  4. 啟動分布式爬蟲

    • 在多臺服務器或多終端分別啟動爬蟲:

      scrapy crawl redis_quotes
      
    • 所有實例會從同一個 Redis 隊列中獲取 URL,去重也基于 Redis,互不重復。

10.4 多機協作示例

  1. 部署多臺服務器(A、B、C),都能訪問同一個 Redis 實例。

  2. 在 A 機上運行:

    redis-server  # 啟動 Redis(可獨立部署)
    
  3. 在 A、B、C 機上,各自拉取完整的 Scrapy 項目代碼,并配置好 settings.py 中的 REDIS_URL

  4. 在 A 機或任意一處,將種子 URL 塞入 Redis:

    redis-cli -h A_ip -p 6379 lpush redis_quotes:start_urls "https://quotes.toscrape.com/"
    
  5. 在 A、B、C 分別運行:

    scrapy crawl redis_quotes
    
    • 三臺機器會自動協調,每臺都從 Redis 隊列中取 URL,去重也由 Redis 統一維護。
  6. 數據收集:

    • 爬取的 Item 通過 RedisPipeline 自動存入 Redis 列表(key: quotes:items);
    • 之后可通過獨立腳本或 pipeline 再將數據持久化到數據庫/文件。

11. 常見反爬與反制策略

11.1 頻率限制與請求頭偽裝

  1. 訪問頻率控制(限速)

    • 對目標站設置隨機或固定延時:

      import time, random
      time.sleep(random.uniform(1, 3))  # 隨機等待 1~3 秒
      
    • Scrapy 中使用 DOWNLOAD_DELAYAUTOTHROTTLE_ENABLED 等。

  2. User-Agent 偽裝

    • 通過隨機 User-Agent 模擬不同瀏覽器。
    • 代碼示例見第 4.6 節。
  3. 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。

  • 模擬登錄流程

    1. 獲取登錄頁 GET 請求,拿到隱藏的 token(如 CSRF);
    2. 結合用戶名/密碼、token,POST 到登錄接口;
    3. 成功后,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 驗證碼識別(簡單介紹)

  • 常見驗證碼類型

    • 驗證碼圖片(扭曲字母/數字);
    • 滑動驗證碼(拼圖/拖動)
    • 點選驗證碼(選特定圖像)
    • 行為生物特征(人機驗證)
  • 常用方案

    1. 簡單 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)
      
    2. 打碼平臺/人工打碼:當驗證碼過于復雜時,可調用第三方打碼平臺 API(如超級鷹、打碼兔等),將圖片發送給平臺,由平臺返回識別結果;或者簡單地由人工識別。

    3. 繞過/獲取接口:很多網站的登錄并不真用驗證碼進行提交,而是在前端校驗。可以抓包找到真實的登錄接口,模擬接口請求,繞過驗證碼。

11.4 代理 IP 池的搭建與旋轉

  1. 為什么要用代理

    • 同一 IP 短時間內請求次數過多容易被封禁;使用代理 IP 池可以不斷切換 IP,降低單 IP 請求頻率。
  2. 獲取代理

    • 免費代理:網上公開的免費代理 IP,但一般不穩定、易失效。可用爬蟲定期從免費代理網站(如 xicidaili、kuaidaili)抓取可用代理,并驗證可用性。
    • 付費代理:阿布云、快代理等付費代理服務,更穩定、更安全。
  3. 搭建本地簡單代理池示例(以免費代理為例,僅供學習)

    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)
    
  4. 在 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 需求分析

  1. 目標數據:新聞標題、摘要(簡介)、文章鏈接、發布時間。
  2. 爬取范圍:首頁頭條新聞(假設分頁結構或動態加載,可視情況調整)。
  3. 存儲方式:MySQL 數據庫,表名 headline_news,字段:id, title, summary, url, pub_date
  4. 反爬策略:設置隨機 User-Agent、下載延時、簡單 IP 偽裝。

12.2 使用 Scrapy + MySQL 完整實現

  1. 創建 Scrapy 項目

    scrapy startproject news_spider
    cd news_spider
    
  2. 安裝依賴

    pip install scrapy pymysql
    
  3. 定義 Item (news_spider/items.py)

    import scrapyclass NewsSpiderItem(scrapy.Item):title = scrapy.Field()summary = scrapy.Field()url = scrapy.Field()pub_date = scrapy.Field()
    
  4. 設置 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,
    }
    
  5. 自定義中間件:隨機 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)
    
  6. 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
    
  7. 編寫 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
    
  8. 運行爬蟲

    • 確保 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() 或正則提取。
  • 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 輪換,防止被封。
  • Q:為什么要隨機 User-Agent?

    • 防止被網站識別為爬蟲。
  • Q:如何在 Scrapy 中使用代理?

    • 參考第 11.4 節,在 DOWNLOADER_MIDDLEWARES 中配置自己的 RandomProxyMiddleware,或直接使用 Scrapy-Proxy-Pool 等庫。

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 提取
parselScrapy 自帶的解析器,支持 CSS/XPathScrapy 項目中快捷解析、項目外獨立解析
PyQuery類似 jQuery 的解析 API,基于 lxml前端同學更習慣 CSS 選擇器,快速上手
re (正則)Python 內置正則模塊,對結構簡單的文本進行模式匹配提取郵箱、電話號碼、URL、數字等簡單模式
html5lib兼容性最強的解析器(支持容錯 HTML),速度相對較慢需要解析結構嚴重不規范的 HTML 時

13.2 瀏覽器自動化

庫 名功能簡介典型場景
Selenium最成熟的瀏覽器自動化框架,支持 Chrome、Firefox、Edge 等需模擬用戶操作 (點擊、滑動、表單提交)、抓取 JS 渲染內容
Playwright微軟出品,繼承 Puppeteer,API 簡潔,支持多瀏覽器高性能 headless 模式,異步/同步模式都支持
PyppeteerPuppeteer 的 Python 移植版Node.js 用戶轉 Python 時快速上手
undetected-chromedriver對抗反爬,屏蔽 Selenium 特征需要更強的逃避檢測能力,尤其面對高級反爬
Splash由 Scrapy-Splash 提供,基于 QtWebKit 的渲染服務Scrapy 與動態渲染結合,用于批量異步渲染

13.3 異步爬取

庫 名功能簡介典型場景
asyncioPython 標準庫,提供事件循環與異步協程基礎編寫異步爬蟲主框架
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 類似,但速度更快,接口更現代更輕量級的瀏覽器自動化
pytesseractOCR 識別圖片文字簡單驗證碼識別
captcha_solver第三方打碼平臺 SDK需要調用付費打碼平臺處理驗證碼
twoCaptcha付費打碼平臺 Python 客戶端需要可靠的驗證碼打碼服務

13.5 反爬與代理

庫 名功能簡介典型場景
fake-useragent隨機生成 User-Agent防止被識別為爬蟲
scrapy-fake-useragentScrapy 專用隨機 UA 插件Scrapy 項目中一鍵啟用隨機 UA
requests-random-user-agent為 requests 提供隨機 UA 支持輕松控制 requests 請求頭
scrapy-rotating-proxiesScrapy 專用代理輪換中間件,用于自動切換代理池(付費或免費)Scrapy 大規模抓取時避免單 IP 封禁
scrapy-proxies開源 Scrapy 代理中間件,可使用免費代理池入門級 Scrapy 項目快速使用代理
proxylist2Python 包,從多個免費代理網站抓取代理 IP自動化維護免費代理列表
requests-redis-rotating-proxies結合 Redis 存儲代理列表,實現高可用代理池中大型項目需集中管理代理 IP
scrapy-user-agentsScrapy 插件,內置常見 UA 列表簡化 Scrapy 中的 UA 列表管理
cfscrape用于繞過 Cloudflare 簡易 JS 保護某些站點需要繞過 Cloudflare 5 秒驗證頁面

13.6 分布式調度

庫 名功能簡介典型場景
scrapy-redisScrapy 分布式爬蟲擴展,統一 Redis 作為隊列與去重存儲分布式 Scrapy 項目
scrapy-cluster基于 Kafka + Redis 的 Scrapy 分布式爬蟲系統企業級分布式環境,需與消息隊列協同
Frigate高性能分布式爬蟲,結合 Redis + MongoDB大規模分布式爬取且需要與 NoSQL 存儲集成
PhantomJS + Splash無頭瀏覽器渲染服務,可與 Scrapy 搭配形成分布式渲染環境需要大規模渲染 JS 頁面后再抓取

13.7 其它有用工具

庫 名功能簡介典型場景
robotparserPython 內置 urllib.robotparser,解析 robots.txt爬蟲前先檢查 robots.txt
tldextract提取域名、子域名、后綴需要對 URL 做域名歸類或統計時
url-normalizeURL 規范化,去除重復查詢參數爬蟲過程對 URL 進行標準化去重
loggingPython 標準庫,用于日志輸出任何爬蟲項目都應進行日志記錄
fake_useragent動態獲取并生成隨機 UA避免 UA 列表過時
termcolor終端字符著色,調試輸出更直觀爬蟲日志、調試時需要彩色提示
psutil系統資源監控,可查看 CPU、內存占用長時間運行爬蟲時監控資源使用情況
schedule定時任務庫,可定時運行腳本需要定時執行爬蟲任務
watchdog文件系統監控,當文件/目錄變化時觸發回調實時監控爬取結果文件、觸發后續任務

說明:因篇幅所限,上表僅列出截至 2024 年底常用或較為穩定的 Python 爬蟲庫,后續可能有新庫或舊庫迭代,請根據實際需求及時查閱官方文檔或社區資源。


14. 附錄

14.1 常見報錯及解決方案

  1. ModuleNotFoundError: No module named 'xxx'

    • 原因:未安裝該包或安裝在全局而非虛擬環境中。
    • 解決:確認當前虛擬環境是否已激活,并執行 pip install xxx
  2. requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]

    • 原因:本機 CA 證書有問題,無法驗證 HTTPS。

    • 解決:

      • 升級 certifipip install --upgrade certifi
      • 臨時忽略:requests.get(url, verify=False)(不推薦用于生產)。
  3. ValueError: too many values to unpack (expected 2) 在 XPath 返回多值時

    • 原因:使用 for x, y in tree.xpath(...),但 XPath 返回值數量與預期不符。
    • 解決:檢查 XPath 語法,或者使用 zip() 將兩個列表匹配。
  4. selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH

    • 原因:chromedriver 未放在系統 PATH,或路徑不正確。
    • 解決:下載與 Chrome 版本一致的 chromedriver,并將其路徑添加到環境變量,或者在代碼中指定 executable_path
  5. pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")

    • 原因:MySQL 用戶名/密碼、權限或 MySQL 服務未啟動。
    • 解決:檢查用戶名、密碼是否正確,MySQL 服務是否運行,數據庫名稱是否存在。
  6. TimeoutErrorasyncio.exceptions.TimeoutError

    • 原因:網絡慢或被目標站點限制。
    • 解決:加大 timeout 參數,降低并發數,適當設置代理。
  7. UnicodeEncodeError/UnicodeDecodeError

    • 原因:處理的文本編碼與 Python 默認編碼不一致。
    • 解決:明確指定 response.encoding = 'utf-8',或者在讀寫文件時加 encoding='utf-8'

14.2 常用 HTTP 狀態碼速查

狀態碼含義
200OK,請求成功
301永久重定向
302臨時重定向
400Bad Request,請求報文語法錯誤
401Unauthorized,需要身份驗證
403Forbidden,服務器拒絕訪問(常見反爬屏蔽碼)
404Not Found,資源不存在
405Method Not Allowed,請求方法被禁止
408Request Timeout,服務器等待客戶端發送請求超時
429Too Many Requests,客戶端請求頻率過高
500Internal Server Error,服務器內部錯誤
502Bad Gateway,服務器作為網關或代理時收到上游服務器無效響應
503Service Unavailable,服務器暫時無法處理請求,常見于流量過大被限流

14.3 學習資源與進階指南

  1. 官方文檔

    • 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/
  2. 推薦書籍

    • 《Python網絡數據采集(第二版)》—— Ryan Mitchell
    • 《深入Python爬蟲框架 Scrapy》—— 黃今
    • 《Python3網絡爬蟲開發實戰》—— 石剛
  3. 課程與視頻

    • B 站、YouTube 上均有優質 Python 爬蟲視頻教程(可搜索“Python 爬蟲 零基礎”、“Scrapy 教程”等)。
    • Coursera/慕課網上的 Python 爬蟲進階課程。
  4. 社區資源

    • Stack Overflow:https://stackoverflow.com/(遇到報錯可搜索)
    • SegmentFault:https://segmentfault.com/(國內開發者社區)
    • GitHub Trending:搜索開源爬蟲項目,學習最佳實踐。

15. 總結

本教程從最基礎的 requests + BeautifulSoup,到 Scrapy 框架、瀏覽器自動化、異步爬蟲、分布式爬蟲,系統梳理了 Python 爬蟲的常見技術與實踐要點,并盤點了截至 2024 年底的主流庫與工具。對于初學者而言,掌握以下幾個關鍵點即可快速上手:

  1. 理解 HTTP 基礎:會構造 GET/POST 請求、分析響應;
  2. 掌握 HTML 解析:熟悉 BeautifulSoup、lxml(XPath/CSS Selector);
  3. 嘗試 Scrapy:學會搭建 Scrapy 項目、編寫 Spider、Pipeline、Settings,并用 Scrapy Shell 調試;
  4. 應對動態頁面:熟練使用 Selenium 或 Playwright 抓取 JS 渲染內容,并結合常規解析方法提取數據;
  5. 探索異步爬蟲:理解協程原理,用 aiohttp、httpx 提升并發性能;
  6. 數據存儲與去重:掌握 CSV/JSON/SQLite/MySQL/MongoDB 的使用,并做好 URL 去重(集合、Redis、Bloom Filter);
  7. 反爬與反制:設置 User-Agent、Referer、下載延時、代理 IP 池等,了解驗證碼處理思路;
  8. 分布式爬蟲:學習 Scrapy-Redis,將任務分配到多臺機器,提高抓取效率。

最后,爬蟲技術更新迅速,截止到本教程編寫時(2024 年底)的主流庫可能會隨著技術迭代、站點反爬升級而發生變化。建議你在入門后,積極關注各大 Python 社區、GitHub Trending 以及官方文檔,及時跟進新特性、新庫、新思路,不斷優化自己的爬蟲方案。祝你能在數據抓取的道路上越走越遠,愉快地玩轉 Python 爬蟲世界!


創作時間:2025 年 6 月 1 日

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916158.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916158.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916158.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

openmv識別數字

Lenet是一種卷積識別網絡,可以用來識別打印的&#xff0c;或者是手寫的數字利用NCC的模板匹配算法來進行數字識別&#xff0c;模板匹配需要我們事先保存需要匹配的數字以及字母的模板圖片,模板匹配對于模板的大小和角度&#xff0c;有一定的要求如果數字的大小和角度有所變換&a…

一款功能全面的文體場所預約小程序

大家好?? ,我是 阿問學長!專注于分享優質開源項目解析、計算機學習資料推薦,并為同學們提供畢業設計項目指導支持,歡迎關注交流!?? 項目概述 隨著全民健身的普及,各地新建了大批體育、健身、文化娛樂場所,中小學校園的運動設施也開始對市民開放。為了合理安排主辦…

PyTorch中實現早停機制(EarlyStopping)附代碼

1. 核心目的 當模型在驗證集上的性能不再提升時&#xff0c;提前終止訓練防止過擬合&#xff0c;節省計算資源 2. 實現方法 監控驗證集指標&#xff08;如損失、準確率&#xff09;&#xff0c;設置耐心值&#xff08;Patience&#xff09; 3. 代碼&#xff1a; class EarlySto…

Nacos-服務注冊,服務發現(一)

nacos快速入手 Nacos是Spring Cloud Alibaba的組件, Spring Cloud Alibaba遵循Spring Cloud中定義的服務注冊, 服 務發現規范. 因此使?Nacos和使?Eureka對于微服務來說&#xff0c;并沒有太?區別. 主要差異在于&#xff1a; Eureka需要??搭建?個服務, Nacos不???搭…

單片機(STM32-ADC模數轉換器)

一、基礎知識1. 模擬信號&#xff08;Analog Signal&#xff09;定義&#xff1a;模擬信號是連續變化的信號&#xff0c;可以取任意數值。特點&#xff1a;幅值和時間都是連續的&#xff0c;沒有“跳變”。舉例&#xff1a;聲音&#xff08;麥克風采集到的電壓&#xff09;溫度…

side.cpp - OpenExo

side.cpp構造函數源代碼run_side - 核心read_data()源代碼FSR壓力傳感器讀取與賦值步態事件檢測&#xff1a;落地&#xff08;ground_strike&#xff09;步態周期自適應&#xff1a;期望步長更新Toe-Off/Toe-On事件檢測與站立/擺動窗口更新步態百分比進度估算FSR閾值動態讀取&a…

基于Java+MySQL實現(Web)文件共享管理系統(仿照百度文庫)

文件共享管理系統的設計與實現摘要&#xff1a;本文件共享管理系統解決了用戶在搜索文件不需要下載文件到本地硬盤后才能查看文件的詳細內容的弊端&#xff1b;解決用戶在搜索關鍵字不明確條件下無法搜索到自己需要的文件弊端&#xff1b;解決了系統用戶并發量增加后服務器宕機…

go語言基礎教程:1. Go 下載安裝和設置

1. Go 下載安裝和設置1. 安裝Go 官網下載安裝即可&#xff0c;注意要記住安裝的位置&#xff0c;例如D:\Go cmd輸入go 或者go env 會輸出各種信息&#xff0c;代表安裝成功 2. hello go &#xff08;1&#xff09;編寫 hello.go go是以文件夾為最小單位管理程序的&#xff0c…

使用相機不同曝光時間測試燈光閃爍頻率及Ai解釋

1.背景坐地鐵上&#xff0c;撥弄著手機拍照中的專業模式&#xff0c;偶然發現拍出了條紋&#xff0c;懷疑是燈光的緣故&#xff0c;但是隨后在家里的LED等下就拍不出類似的效果了。好奇心?讓我又嘗試多了解了一點和不斷嘗試&#xff0c;發現不同的曝光時間可以拍出不同明顯程度…

力扣-416.分割等和子集

題目鏈接 416.分割等和子集 class Solution {public boolean canPartition(int[] nums) {int sum 0;for (int i 0; i < nums.length; i) {sum nums[i];}if (sum % 2 1)return false;int target sum / 2;// dp[i]表示&#xff1a;背包容量為i時&#xff0c;能裝的最大…

http協議學習-body各種類型

1、概述使用postman工具和nc命令分析http協議中body各種類型的格式。2、分析環境準備虛擬機中用nc命令模仿服務器&#xff0c;啟動監聽狀態。 windows機器安裝postmannc -k -l 192.168.202.223 80821、params參數postman中params添加倆個key為m、n&#xff1b;value為1、2&…

C++中的塔尖算法(Tarjan算法)詳解

C中的塔尖算法&#xff08;Tarjan算法&#xff09;詳解——目錄C中的塔尖算法&#xff08;Tarjan算法&#xff09;詳解一、什么是Tarjan算法&#xff1f;二、算法原理與實現步驟1. 核心概念2. 主要邏輯3. C代碼示例三、應用場景與擴展1. 典型應用2. 注意事項四、為什么選擇Tarj…

Qt 數據庫事務處理與數據安全

在 Qt 應用程序中&#xff0c;數據庫事務處理是確保數據完整性和一致性的關鍵技術。通過事務&#xff0c;可以將多個數據庫操作作為一個不可分割的單元執行&#xff0c;保證數據在并發訪問和異常情況下的安全性。本文將詳細介紹 Qt 中數據庫事務的處理方法和數據安全策略。 一、…

Redis的事務和Lua之間的區別

Redis的事務和Lua之間的區別 Redis 提供了事務和 Lua 腳本兩種實現原子性操作的方式。當需要以原子方式執行多個命令時,我們可以選擇其中一種方案。 原子性保證 兩者都確保操作的不可分割性 需要注意:不管是事務還是 Lua 腳本都不支持回滾機制 區別: 事務:某個命令失敗不會…

騰訊云SDK

SDK的用途&#xff0c;現在顯然是想更系統地了解它的產品定位和核心能力。 用戶可能是開發者或者技術決策者&#xff0c;正在評估騰訊云的開發工具鏈。從ta連續追問云服務相關技術細節的習慣看&#xff0c;應該具備相當的技術背景&#xff0c;但需要避免過度使用術語。 需要突出…

大數據集分頁優化:LIMIT OFFSET的替代方案

針對大數據集分頁場景中 LIMIT OFFSET 的性能瓶頸&#xff0c;以下是已驗證的高效替代方案及實施要點&#xff1a;?? 一、LIMIT OFFSET 的核心問題當偏移量&#xff08;OFFSET&#xff09;增大時&#xff0c;數據庫需?物理掃描并丟棄前 N 條記錄?&#xff0c;導致資源浪費和…

Linux網絡框架分析

在 Linux 內核架構中,/net 和 /drivers/net 是網絡子系統的兩個核心組成部分,它們之間的關系體現了 Linux 經典的 “抽象層分離” 設計哲學。以下是深入分析: 一、核心關系圖解 #mermaid-svg-esFw9i3LN65SYumi {font-family:"trebuchet ms",verdana,arial,sans-se…

ISIS高級特性GR

一、概述IS-IS GR是一種支持GR能力的高可靠性技術&#xff0c;可以實現數據的不間斷轉發。與我們之前介紹的OSPF的GR功能幾乎一致,但實現方法并不相同。1、GR支持GR的ISIS的設備,IIH報文中一定會攜帶TLV211(GR),TLV211包含的字段(1)RR:restart request 請求重啟,默認是3秒發送1…

電廠液壓執行器自動化升級:Modbus TCP與DeviceNet的協議貫通實踐

一、項目背景在我們電廠的汽輪機控制區&#xff0c;液壓執行器是實打實的“關鍵選手”——從調節蒸汽閥門開度到控制閘板起落&#xff0c;全靠它在高壓環境下精準動作。但這套系統一直有個“溝通障礙”&#xff1a;負責統籌控制的施耐德PLC走Modbus TCP協議&#xff0c;而液壓執…

ucharts 搭配uniapp 自定義x軸文字 實現截取顯示

formatter格式化問題因為組件不能傳遞 function&#xff0c;所有的 formatter 均需要變成別名 format 來定義&#xff0c;并在 config-ucharts.js 或 config-echarts.js 配置對應的 formatter 方法&#xff0c;組件會根據 format 的值自動替換配置文件中的 formatter 方法。uCh…