一、爬虫初印象#
インターネットの広大な世界では、データは宝物のようにあちこちに散らばっています。そして、クローラーは特定のルールに従って自動的にウェブページを行き来し、私たちが必要とする情報を取得する勤勉な宝探し者のような存在です。簡単に言えば、クローラーはウェブデータを自動的に取得するプログラムまたはスクリプトであり、その正式名称はウェブクローラー(Web Crawler)で、ウェブスパイダーやネットワークロボットとも呼ばれます。
クローラーはデータ取得において重要な役割を果たしています。現在、データは企業や研究者の意思決定の重要な根拠となっており、クローラーは大量のデータを効率的に取得する手段です。その応用シーンは非常に広範で、データ分析の分野では、クローラーを使用してソーシャルメディアプラットフォーム上のユーザーコメントや行動データを収集し、企業がユーザーのニーズや市場動向を正確に洞察し、製品の最適化やマーケティング戦略の策定に強力な支援を提供します。競合調査においては、クローラーが競合他社の製品情報、価格動向、プロモーション活動などを定期的に取得し、企業が迅速に戦略を調整し、競争力を維持するのに役立ちます。さらに、学術研究やニュース情報の集約などの分野でも、クローラーは不可欠な役割を果たしています。
二、環境搭建与基础语法#
2.1 Python 安装与配置#
Python はクローラー開発の第一選択言語であり、そのシンプルな構文と豊富なライブラリは開発プロセスを大幅に簡素化します。まず、Python の公式ウェブサイト(https://www.python.org/downloads/)から、あなたのオペレーティングシステムに適したインストーラをダウンロードする必要があります。ダウンロードページでは、さまざまなバージョンの Python が表示されますので、最新の安定版を選択することをお勧めします。ダウンロードが完了したら、インストーラを実行し、インストールウィザードで「Add Python to PATH」オプションにチェックを入れることが非常に重要です。このステップは、Python がシステムの任意のパスから呼び出されることを保証します。
インストールが完了したら、コマンドプロンプト(CMD)でpython --version
と入力して、インストールが成功したかどうかを確認できます。成功した場合、Python のバージョン情報が表示されます。また、python
と入力して Python のインタラクティブ環境に入ることもでき、ここで直接 Python コードを作成して実行し、Python の魅力を体験できます。
2.2 开发工具选择#
良い開発ツールは開発効率を大幅に向上させることができます。クローラー開発において、PyCharm は非常に人気のある統合開発環境(IDE)です。コードの自動補完、構文ハイライト、コードナビゲーションなどの強力なコード編集機能を備えており、コードを書く際により快適に作業できます。また、PyCharm は Python のさまざまなライブラリやフレームワークを良好にサポートしており、プロジェクト管理やデバッグが容易です。
PyCharm の他にも、Visual Studio Code(VS Code)などの優れた選択肢があります。これは軽量でありながら強力なコードエディタで、Python プラグインをインストールすることで効率的な Python 開発が可能になります。VS Code は優れた拡張性とクロスプラットフォーム性を持ち、シンプルな開発環境を好む開発者に適しています。
2.3 Python 基础语法回顾#
正式にクローラー開発を始める前に、Python の基本構文を振り返ることは非常に重要です。これにはデータ型、制御文、関数などが含まれます。
Python には整数(int)、浮動小数点数(float)、文字列(str)、ブール値(bool)などの基本データ型がいくつかあります。異なるデータ型はデータの保存や操作においてそれぞれ特徴があります。例えば、文字列はテキスト情報を保存するために使用され、インデックスやスライス操作を通じて文字列内の特定の文字や部分文字列を取得できます。サンプルコードは以下の通りです:
name = "クローラー小能手"
print(name[0]) # 最初の文字を出力
print(name[2:5]) # 3文字目から5文字目までの部分文字列を出力
制御文はプログラムのロジックの重要な構成要素であり、一般的には条件文(if - elif - else)やループ文(for、while)があります。条件文は異なる条件に基づいて異なるコードブロックを実行するために使用され、ループ文は特定のコードを繰り返し実行するために使用されます。例えば、for ループを使用してリストを反復処理することができます:
fruits = ["リンゴ", "バナナ", "オレンジ"]
for fruit in fruits:
print(fruit)
関数は再利用可能なコードの一部をカプセル化するためのツールであり、コードの再利用性と可読性を向上させることができます。Python ではdef
キーワードを使用して関数を定義できます。例えば:
def add_numbers(a, b):
return a + b
result = add_numbers(3, 5)
print(result) # 8を出力
これらの基本構文をマスターすることで、今後のクローラー開発のための堅固な基盤を築くことができます。
三、爬虫基础原理与流程#
3.1 HTTP 协议解析#
HTTP プロトコル、すなわちハイパーテキスト転送プロトコルは、クローラーとウェブサーバー間の通信の基礎です。これはクローラーとサーバー間の共通言語のようなもので、双方がデータの要求と転送をどのように行うかを規定しています。
HTTP リクエストは主にリクエストライン、リクエストヘッダー、リクエストボディ(オプション)で構成されています。リクエストラインにはリクエストメソッド、URL、HTTP バージョンが含まれます。一般的なリクエストメソッドには GET と POST があります。GET メソッドは通常、サーバーからリソースを取得するために使用されます。例えば、ウェブページにアクセスする際、ブラウザはサーバーに GET リクエストを送信し、ウェブページの HTML 内容を取得します。GET リクエストを使用する際、パラメータは URL の末尾にキーと値のペアの形式で付加されます。例えば、https://example.com/search?q=クローラー&page=1
のように、パラメータが URL に表示されるため、機密情報の転送にはあまり適していません。
POST メソッドは通常、サーバーにデータを送信するために使用されます。例えば、ログインフォームやコメントの送信などの操作です。GET とは異なり、POST リクエストのパラメータはリクエストボディに置かれ、ユーザーには見えず、安全性が相対的に高いです。例えば、ログイン時にユーザー名とパスワードが POST リクエストでサーバーに送信され、リクエストボディにはusername=admin&password=123456
のような内容が含まれる可能性があります。
HTTP レスポンスはステータスライン、レスポンスヘッダー、レスポンスボディで構成されています。ステータスラインのステータスコードは、リクエストの処理結果を直感的に反映します。例えば、200 はリクエストが成功し、サーバーが要求されたリソースを正常に返したことを示します。404 は要求されたリソースが存在しないことを示し、URL の入力ミスやページが削除された可能性があります。500 はサーバー内部でエラーが発生したことを示します。レスポンスヘッダーにはレスポンスに関するメタ情報が含まれており、コンテンツタイプ(例えば、text/html
は HTML ページが返されることを示します)、コンテンツの長さなどが含まれます。そして、レスポンスボディは私たちが本当に取得したいデータ、例えばウェブページの HTML コードや JSON 形式のデータなどです。
3.2 爬虫工作流程#
クローラーの作業フローは、リクエストの発行、レスポンスの取得、データの解析、データの保存といういくつかの重要なステップに要約できます。
まず、クローラーは設定された URL に基づいて、HTTP ライブラリ(Python のrequests
ライブラリなど)を使用してターゲットサーバーにリクエストを発行します。この過程で、実際のユーザーのアクセスを模倣するために、リクエストヘッダーを設定することがあります。例えば、User-Agent
は、サーバーに訪問者が使用しているブラウザの種類やオペレーティングシステムなどの情報を伝えることができます。以下のコードは、requests
ライブラリを使用して GET リクエストを発行する例です:
import requests
url = "https://example.com"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
サーバーがリクエストを受信すると、対応するレスポンスを返します。リクエストが成功した場合、ステータスコード、レスポンスヘッダー、レスポンスボディを含むレスポンスオブジェクトを取得します。クローラーはレスポンスを取得した後、次にレスポンスボディから必要なデータを抽出します。このステップでは、データの形式に応じて適切な解析方法を選択する必要があります。レスポンスボディが HTML 形式の場合、BeautifulSoup
やlxml
などのライブラリを使用して解析できます。例えば、BeautifulSoup
を使用して HTML ページを解析し、すべてのリンクを抽出することができます:
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a')
for link in links:
print(link.get('href'))
レスポンスボディが JSON 形式のデータである場合、Python の組み込みjson
モジュールを使用して解析できます。以下はその例です:
import json
data = json.loads(response.text)
print(data)
最後に、解析したデータをローカルファイルやデータベースに保存し、後の分析や使用のために準備します。ファイルに保存する一般的な形式には、テキストファイル(.txt
)、CSV ファイル(.csv
)、JSON ファイル(.json
)などがあります。例えば、データを JSON ファイルとして保存するには:
import json
data = [{"name": "クローラー", "info": "データ収集ツール"}]
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
データベースに保存する必要がある場合、リレーショナルデータベース(MySQL など)にはpymysql
ライブラリを使用し、非リレーショナルデータベース(MongoDB など)にはpymongo
ライブラリを使用できます。
四、爬虫常用库实战#
4.1 Requests 库#
Requests ライブラリは Python で HTTP リクエストを送信するための強力なツールであり、その API はシンプルで明確で、ウェブサーバーとのインタラクションを容易にします。Requests ライブラリを使用する際は、まずインストールされていることを確認し、pip install requests
コマンドでインストールできます。
インストールが完了したら、コード内で使用できます。例えば、ウェブページの内容を取得するためにシンプルな GET リクエストを送信するには:
import requests
url = "https://www.example.com"
response = requests.get(url)
if response.status_code == 200:
print(response.text)
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
この例では、requests.get(url)
が指定された URL に GET リクエストを送信し、レスポンスオブジェクトresponse
を返します。response.status_code
をチェックすることで、リクエストが成功したかどうかを判断できます。ステータスコードが 200 の場合、リクエストが成功し、response.text
にはウェブページの HTML 内容が含まれています。
GET リクエストの他に、Requests ライブラリは POST リクエストもサポートしており、サーバーにデータを送信するために使用されます。例えば、ログインフォームの送信を模倣するには:
import requests
url = "https://www.example.com/login"
data = {
"username": "your_username",
"password": "your_password"
}
response = requests.post(url, data=data)
print(response.text)
このコードでは、data
辞書にログインに必要なユーザー名とパスワードが含まれ、requests.post(url, data=data)
がこれらのデータを指定されたログイン URL に送信します。
さらに、リクエストヘッダーを設定して異なるブラウザのアクセスを模倣したり、レスポンスの JSON データを処理したり、リクエストのタイムアウトを設定したりすることもできます。例えば、リクエストヘッダーを設定するには:
import requests
url = "https://www.example.com"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
print(response.text)
この例では、headers
辞書がUser-Agent
を設定し、サーバーに私たちが Chrome ブラウザを使用していることを伝えます。これにより、一部のウェブサイトが非ブラウザアクセスを検出してリクエストを拒否するのを回避できます。
4.2 BeautifulSoup 库#
BeautifulSoup ライブラリは、HTML および XML データを解析するための強力なツールです。複雑な HTML または XML 文書を簡単に遍歴および操作できるツリー構造に変換し、必要なデータを簡単に抽出できます。BeautifulSoup ライブラリを使用する前に、pip install beautifulsoup4
コマンドでインストールする必要があります。
Requests ライブラリを使用してウェブページの HTML 内容を取得したと仮定して、次に BeautifulSoup ライブラリを使用して解析します。例えば:
from bs4 import BeautifulSoup
import requests
url = "https://www.example.com"
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
# すべてのリンクを抽出
links = soup.find_all('a')
for link in links:
print(link.get('href'))
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
このコードでは、BeautifulSoup(response.text, 'html.parser')
が取得した HTML 内容をBeautifulSoup
オブジェクトsoup
に解析します。html.parser
はパーサーで、ここでは Python 内蔵の HTML パーサーを使用していますが、必要に応じて他のパーサー(例えばlxml
)を選択することもできます。soup.find_all('a')
はすべての<a>
タグ、つまりリンクを検索し、link.get('href')
を使用して各リンクのhref
属性値を取得します。
タグ名を使用して要素を検索するだけでなく、クラス名や ID などの属性を使用して検索することもできます。例えば、特定のクラス名を持つ要素を検索するには:
from bs4 import BeautifulSoup
import requests
url = "https://www.example.com"
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
# クラス名が "special-class" の要素を検索
special_elements = soup.find_all(class_='special-class')
for element in special_elements:
print(element.get_text())
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
この例では、soup.find_all(class_='special-class')
がクラス名がspecial-class
のすべての要素を検索し、element.get_text()
を使用してこれらの要素のテキスト内容を取得します。
4.3 XPath 语法#
XPath は、XML および HTML 文書内の要素を位置付けて抽出するための言語です。パス式を定義することで、文書内のノードまたはノードセットを正確に選択でき、クローラー開発において重要な応用があります。Python では、lxml
ライブラリと組み合わせて XPath 構文を使用できます。まず、lxml
ライブラリをインストールする必要があり、pip install lxml
コマンドでインストールできます。
以下は、XPath 構文を使用してウェブデータを抽出する例です:
from lxml import etree
import requests
url = "https://www.example.com"
response = requests.get(url)
if response.status_code == 200:
html = etree.HTML(response.text)
# すべての <p> タグのテキスト内容を抽出
p_texts = html.xpath('//p/text()')
for text in p_texts:
print(text)
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
このコードでは、etree.HTML(response.text)
が取得した HTML 内容をlxml
のElement
オブジェクトhtml
に変換します。html.xpath('//p/text()')
は XPath 式//p/text()
を使用してすべての<p>
タグ内のテキスト内容を選択します。ここで、//
は現在のノードから文書内のノードを選択し、その位置を考慮しません。p
はタグ名で、/text()
はそのタグ内のテキストを選択します。
XPath 構文は、属性を使用して要素を位置付けることもサポートしています。例えば、特定の属性値を持つ要素を抽出するには:
from lxml import etree
import requests
url = "https://www.example.com"
response = requests.get(url)
if response.status_code == 200:
html = etree.HTML(response.text)
# classが "article-content" の <div> タグ内のすべてのリンクを抽出
links = html.xpath('//div[@class="article-content"]//a/@href')
for link in links:
print(link)
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
この例では、//div[@class="article-content"]
はすべてのclass
属性値がarticle-content
の<div>
タグを選択し、//a/@href
はこれらの<div>
タグ内のすべての<a>
タグのhref
属性値を選択します。
4.4 正则表达式#
正規表現は、文字列をマッチさせたり処理したりするための強力なツールであり、クローラーのデータ抽出にも頻繁に使用されます。特定のパターンに一致する文字列をマッチさせるために一連のルールを定義します。Python では、組み込みのre
モジュールを使用して正規表現をサポートしています。
例えば、テキストからすべての電話番号を抽出する場合、次のような正規表現を使用できます:
import re
text = "連絡先電話番号:13888888888、別の電話:15666666666"
pattern = r'\d{11}'
phones = re.findall(pattern, text)
for phone in phones:
print(phone)
このコードでは、r'\d{11}'
が正規表現パターンです。ここで、r
はこれは生の文字列であり、バックスラッシュ文字がエスケープされないようにします。\d
は任意の数字文字(0 - 9)をマッチさせ、{11}
は前の文字(つまり数字)が連続して 11 回出現することを示します。re.findall(pattern, text)
は、与えられたテキストtext
内で正規表現パターンpattern
に一致するすべての文字列を検索し、リストを返します。
正規表現は、電子メールアドレスや URL などのより複雑なパターンをマッチさせるためにも使用できます。例えば、電子メールアドレスをマッチさせるには:
import re
text = "メールアドレス:[email protected]、別のメールアドレス:[email protected]"
pattern = r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'
emails = re.findall(pattern, text)
for email in emails:
print(email)
この例では、[a-zA-Z0-9_.+-]+
は文字、数字、アンダースコア、ドット、プラス、マイナスからなる 1 つ以上の文字を示し、@
は電子メールアドレスの固定記号です。[a-zA-Z0-9-]+
は文字、数字、マイナスからなる 1 つ以上の文字を示し、\.[a-zA-Z0-9-.]+
はドットの後に文字、数字、ドット、マイナスからなる 1 つ以上の文字が続くことを示します。この正規表現パターンは、一般的な電子メールアドレス形式を正確にマッチさせることができます。
五、爬虫进阶技巧#
5.1 处理反爬虫机制#
クローラーの旅の中で、私たちはしばしばウェブサイトの反クローリングメカニズムに遭遇します。これはまるで宝探しの道中で多くの障害に直面するようなものです。しかし心配しないでください、私たちには一連の効果的な対策があります。
リクエストヘッダーを設定することは、シンプルで効果的な方法です。ウェブサイトはしばしばリクエストヘッダー内のUser-Agent
などの情報を検出して、リクエストがクローラーから来ているかどうかを判断します。私たちは実際のブラウザのリクエストヘッダーを模倣することで、ウェブサイトに普通のユーザーがアクセスしていると思わせることができます。例えば、Python のrequests
ライブラリでリクエストヘッダーを設定するには、次のようにします:
import requests
url = "https://example.com"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
ここでのUser-Agent
文字列は Chrome ブラウザの情報を模倣しており、この方法によってリクエストの信頼性を高めることができます。
プロキシ IP を使用することも、反クローリング制限を突破するための重要な手段です。私たちの IP アドレスが頻繁なリクエストのためにウェブサイトに禁止された場合、プロキシ IP は私たちの「代理」となり、ウェブサイトへのアクセスを続けるのに役立ちます。無料または有料のプロキシ IP サービスを使用することができ、Python ではrequests
ライブラリを使用してプロキシ IP を設定する例は次の通りです:
import requests
url = "https://example.com"
proxies = {
"http": "http://your_proxy_ip:your_proxy_port",
"https": "https://your_proxy_ip:your_proxy_port"
}
response = requests.get(url, proxies=proxies)
プロキシ IP を使用する際は、信頼できるプロキシソースを選択し、プロキシ IP の安定性と可用性を確保することが重要です。
さらに、リクエストの頻度を制御することも非常に重要です。短時間にウェブサイトに大量のリクエストを送信すると、クローラーとして認識されやすくなります。私たちは時間間隔を設定することで、リクエストをより「穏やか」にすることができます。例えば、time
モジュールのsleep
関数を使用して、各リクエストの後に一定の時間を待機することができます:
import requests
import time
url_list = ["https://example1.com", "https://example2.com", "https://example3.com"]
for url in url_list:
response = requests.get(url)
time.sleep(5) # 5秒待機
こうすることで、5 秒ごとにリクエストを送信し、反クローリングメカニズムに検出されるリスクを低減します。
5.2 动态网页抓取#
ウェブ技術の進展に伴い、ますます多くのウェブページが動的読み込み技術を採用しており、これがクローラーに新たな課題をもたらしています。従来の HTML 内容を直接取得する方法では、動的に読み込まれるデータを取得できない場合があります。しかし、私たちにはこの状況に対応するための特別なツールがあります。
Selenium は強力な自動化テストツールであり、実際のユーザーがブラウザ内で操作するのを模倣することで、動的ウェブページの完全な内容を取得できます。Selenium を使用するには、まず対応するブラウザドライバをインストールする必要があります。Chrome ブラウザの場合、ChromeDriver のウェブサイトからブラウザバージョンに一致するドライバをダウンロードします。インストールが完了したら、pip install selenium
で Selenium ライブラリをインストールします。以下は、Selenium を使用してウェブページを開き、内容を取得する例です:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://example.com")
# ウェブページの内容を取得
page_source = driver.page_source
print(page_source)
driver.quit()
この例では、webdriver.Chrome()
が Chrome ブラウザドライバのインスタンスを作成し、driver.get(url)
が指定されたウェブページを開き、driver.page_source
がウェブページのソースコードを取得し、最後にdriver.quit()
がブラウザを閉じます。
Selenium の他にも、Scrapy - Splash も良い選択肢です。これは Scrapy フレームワークのプラグインで、動的ウェブページを処理するために特化しています。Splash は JavaScript レンダリングに基づくサービスで、サーバー側で JavaScript をレンダリングし、レンダリングされた HTML をクローラーに返します。Scrapy - Splash を使用するには、まず Splash サービスをインストールし、Scrapy プロジェクトで適切な設定を行います。設定が完了したら、クローラーコード内で Splash を使用して動的ウェブページを処理できます。例えば、Scrapy のsettings.py
ファイルに次の設定を追加します:
SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
'scrapy.downloader.middlewares.httpcompression.HttpCompressionMiddleware': 810,
'scrapy_splash.SplashMiddleware': 820,
}
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
'scrapy_splash.SplashSpiderMiddleware': 725,
}
DUPEFILTER_CLASS ='scrapy_splash.SplashAwareDupeFilter'
HTTPCACHE_STORAGE ='scrapy_splash.SplashAwareFSCacheStorage'
次に、クローラーコード内で Splash のRequest
オブジェクトを使用してリクエストを送信します:
from scrapy_splash import SplashRequest
class MySpider(scrapy.Spider):
name = "my_spider"
start_urls = ["https://example.com"]
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(url, self.parse, args={'wait': 5})
def parse(self, response):
# ウェブページの内容を解析
pass
この例では、SplashRequest
がリクエストを Splash サービスに送信し、args={'wait': 5}
はページの JavaScript コードが十分にレンダリングされるまで 5 秒待機してから内容を取得することを示します。
5.3 多线程与异步爬虫#
データ量が多い場合、単一スレッドのクローラーの効率は比較的低くなる可能性があります。この場合、マルチスレッドや非同期プログラミング技術を利用してクローラーの効率を向上させることができます。
マルチスレッドクローラーは、複数のスレッドを同時に起動し、各スレッドが 1 つまたは複数の URL のリクエストとデータ抽出を担当することで、データ収集の速度を大幅に向上させることができます。Python では、threading
モジュールを使用してマルチスレッドクローラーを実現できます。例えば:
import threading
import requests
def fetch_url(url):
response = requests.get(url)
print(response.text)
url_list = ["https://example1.com", "https://example2.com", "https://example3.com"]
threads = []
for url in url_list:
t = threading.Thread(target=fetch_url, args=(url,))
threads.append(t)
t.start()
for t in threads:
t.join()
このコードでは、threading.Thread(target=fetch_url, args=(url,))
が新しいスレッドを作成し、target
がスレッドが実行する関数を指定し、args
が関数に必要な引数を渡します。この方法で、複数のスレッドが異なる URL に対して同時にリクエストを発行し、クローラーの効率を向上させます。
非同期クローラーは、Python の非同期プログラミング機能を利用して、1 つのスレッド内で非ブロッキングの I/O 操作を実現します。ネットワークリクエストを待機している間に、プログラムは他のタスクを実行できるため、スレッドのブロックを回避し、リソースの利用率を向上させます。asyncio
は Python で非同期プログラミングに使用される標準ライブラリで、aiohttp
ライブラリ(非同期 HTTP リクエスト用)と組み合わせることで、高効率な非同期クローラーを実現できます。サンプルコードは以下の通りです:
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example1.com", "https://example2.com", "https://example3.com"]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for result in results:
print(result)
if __name__ == "__main__":
asyncio.run(main())
この例では、async def
が非同期関数を定義し、await
が非同期操作の完了を待機します。aiohttp.ClientSession()
が HTTP セッションを作成し、tasks
リストがすべての非同期タスクを含み、asyncio.gather(*tasks)
がこれらのタスクを並行して実行し、すべてのタスクが完了するのを待ちます。この方法で、高効率な非同期クローラーを実現します。
六、爬虫框架应用#
6.1 Scrapy 框架#
Scrapy は強力で広く使用されている Python クローラーフレームワークであり、クローラー開発に高効率で便利なソリューションを提供します。
Scrapy のアーキテクチャは、精密な機械のようで、複数のコアコンポーネントが協調して動作します。その中で、エンジン(Engine)はフレームワークのコアであり、各コンポーネント間の通信とデータの流れを調整します。エンジンはスケジューラ(Scheduler)からクローリングする URL を取得し、リクエストをダウンローダー(Downloader)に送信します。ダウンローダーはネットワークからウェブページの内容をダウンロードし、レスポンスをエンジンに返します。エンジンはレスポンスをクローラー(Spider)に渡してデータを解析します。そして、パイプライン(Pipeline)はクローラーが抽出したデータを処理し、データのクレンジングや保存などの操作を行います。スケジューラはインテリジェントなタスク配分器のように機能し、URL キューを維持し、クローリングする URL の管理とスケジューリングを担当し、各 URL が合理的にクローリング順序を割り当てられることを保証し、重複する URL の処理も行います。
Scrapy フレームワークを使用するには、まず Scrapy プロジェクトを作成する必要があります。コマンドラインでscrapy startproject プロジェクト名
と入力することで、プロジェクトフレームワークを迅速に作成できます。例えば、my_crawler
という名前のプロジェクトを作成するには、次のコマンドを実行します:
scrapy startproject my_crawler
プロジェクトディレクトリに移動したら、scrapy genspider クローラー名 目標ドメイン名
コマンドを使用してクローラーを作成できます。例えば、example.com
ウェブサイトのデータをクローリングする場合、クローラーを作成するコマンドは次の通りです:
cd my_crawler
scrapy genspider example_spider example.com
生成されたクローラーファイル内で、クローラーのロジックを定義する必要があります。例えば、以下は指定されたウェブページのタイトル情報をクローリングするためのシンプルなクローラーの例です:
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example_spider"
allowed_domains = ["example.com"]
start_urls = ["https://example.com"]
def parse(self, response):
titles = response.css('title::text').extract()
for title in titles:
yield {'title': title}
この例では、parse
メソッドがクローラーのコアロジック部分であり、CSS セレクタを使用してウェブページ内のタイトル情報を抽出し、yield
を使用してデータをパイプラインに渡して後続の処理を行います。
6.2 PySpider 框架#
PySpider は軽量でありながら強力なクローラーフレームワークであり、独自の特徴と適用シーンを持っています。
PySpider の大きな特徴は、直感的で使いやすい WebUI インターフェースを提供していることです。このインターフェースを通じて、開発者はプロジェクト管理、タスク監視、結果の確認を簡単に行うことができます。WebUI では、クローラータスクを簡単に作成、編集、起動し、クローラーの実行状態をリアルタイムで把握し、収集したデータ結果を確認できるため、開発とデバッグの効率が大幅に向上します。
PySpider は MySQL、MongoDB、Redis などのさまざまなデータストレージ方式をサポートしています。これにより、開発者はプロジェクトの実際のニーズに応じて最適なデータストレージソリューションを柔軟に選択し、後続のデータ処理や分析を容易に行うことができます。
また、強力な分散クローリング機能も備えています。複数のクローラーノードを設定することで、PySpider は高い並行性のクローリングタスクを実現し、データ収集の速度と効率を大幅に向上させます。この特性により、大規模なデータクローリングタスクの処理において優れたパフォーマンスを発揮します。
例えば、PySpider を使用してニュースサイトの文章内容をクローリングする場合、まず PySpider をインストールし、pip install pyspider
コマンドでインストールします。インストールが完了したら、PySpider サービスを起動し、pyspider all
コマンドを入力します。ブラウザでhttp://localhost:5000
にアクセスし、PySpider の WebUI インターフェースに入ります。WebUI で新しいクローラープロジェクトを作成し、以下のクローラーコードを記述します:
from pyspider.libs.base_handler import *
class NewsSpider(BaseHandler):
crawl_config = {}
@every(minutes=24 * 60)
def on_start(self):
self.crawl('https://news.example.com', callback=self.index_page)
def index_page(self, response):
for each in response.doc('a[href^="http"]').items():
self.crawl(each.attr.href, callback=self.detail_page)
def detail_page(self, response):
title = response.doc('title').text()
content = response.doc('.article-content').text()
return {'title': title, 'content': content}
この例では、on_start
メソッドがクローラーの起始 URL を定義し、index_page
メソッドがリストページを解析して記事リンクを抽出し、detail_page
メソッドで詳細ページを解析して最終的に記事のタイトルと内容を抽出します。PySpider の WebUI インターフェースを通じて、このクローラータスクを簡単に起動、監視、管理できます。
七、实战项目演练#
7.1 小型爬虫项目#
皆さんにクローラーの魅力をより直感的に感じてもらうために、豆瓣映画 Top250 をクローリングする例を挙げて、完全なクローラー実装プロセスを示します。豆瓣映画 Top250 は映画愛好者が注目する人気ランキングで、豊富な映画情報が含まれています。
まず、ウェブページの構造を分析する必要があります。ブラウザの開発者ツール(例えば Chrome ブラウザの F12 ショートカットキー)を使用して、ウェブページの HTML ソースコードを確認し、映画情報が含まれるタグや属性を見つけます。例えば、映画タイトルは通常<span class="title">
タグ内にあり、評価は<span class="rating_num">
タグ内にあります。
次に、クローラーコードを作成します。Python のrequests
ライブラリとBeautifulSoup
ライブラリを使用して、コードは以下の通りです:
import requests
from bs4 import BeautifulSoup
import csv
def get_movie_info(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
movie_list = soup.find_all('div', class_='item')
for movie in movie_list:
title = movie.find('span', class_='title').text
rating = movie.find('span', class_='rating_num').text
quote = movie.find('span', class_='inq')
quote = quote.text if quote else '無'
yield {
'title': title,
'rating': rating,
'quote': quote
}
else:
print(f"リクエスト失敗、ステータスコード: {response.status_code}")
def save_to_csv(data, filename='douban_movies.csv'):
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = ['title', 'rating', 'quote']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for movie in data:
writer.writerow(movie)
if __name__ == "__main__":
base_url = "https://movie.douban.com/top250?start={}&filter="
all_movie_info = []
for start in range(0, 250, 25):
url = base_url.format(start)
movie_info = get_movie_info(url)
all_movie_info.extend(movie_info)
save_to_csv(all_movie_info)
このコードでは、get_movie_info
関数がリクエストを送信し、ウェブページを解析して映画のタイトル、評価、概要情報を抽出します。save_to_csv
関数は抽出したデータを CSV ファイルとして保存します。異なるページ番号をループして、豆瓣映画 Top250 のすべての情報を取得できます。
7.2 大型综合爬虫项目#
次に、より挑戦的なタスクに取り組みます。電商プラットフォームの製品情報をクローリングし、データの永続化と分散クローラー機能を実現します。特定の電商プラットフォームのスマートフォン製品情報をクローリングする例を挙げます。このプロセスには複数の複雑なステップが含まれます。
まず、反クローリング問題を解決する必要があります。電商プラットフォームは通常、厳格な反クローリングメカニズムを持っているため、リクエストヘッダーを設定したり、プロキシ IP を使用したりしてリクエストを偽装します。また、データの永続化を実現するために、データを MySQL データベースに保存することを選択します。以下はScrapy
フレームワークを使用して実装した部分的なコード例です:
import scrapy
import pymysql
class MobileSpider(scrapy.Spider):
name = "mobile_spider"
allowed_domains = ["example.com"]
start_urls = ["https://example.com/mobiles"]
def parse(self, response):
for mobile in response.css('.mobile-item'):
item = {
'title': mobile.css('.title::text').get(),
'price': mobile.css('.price::text').get(),
'rating': mobile.css('.rating::text').get()
}
yield item
next_page = response.css('.next-page::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
class MySQLPipeline:
def __init__(self):
self.conn = pymysql.connect(
host='localhost',
user='root',
password='password',
db='ecommerce',
charset='utf8'
)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
sql = "INSERT INTO mobiles (title, price, rating) VALUES (%s, %s, %s)"
values = (item['title'], item['price'], item['rating'])
self.cursor.execute(sql, values)
self.conn.commit()
return item
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
このコードでは、MobileSpider
クラスがクローラーのロジックを定義し、起始 URL、データ解析、ページネーション処理を行います。MySQLPipeline
クラスはクローリングしたデータを MySQL データベースのmobiles
テーブルに挿入する役割を担います。
分散クローラーについては、Scrapy - Redis
フレームワークを利用して実現できます。Scrapy - Redis
はクローリングタスクを複数のノードに分配して並行実行し、クローリング効率を大幅に向上させます。まず、Scrapy - Redis
ライブラリをインストールし、pip install scrapy-redis
コマンドでインストールします。次に、settings.py
ファイルで次のように設定します:
# Redisを使用してリクエストキューを管理
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# すべてのクローラーが同じ重複フィンガープリンターを共有することを保証
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# Redis接続設定
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
クローラークラスでは、RedisSpider
クラスを継承します。以下のようにします:
from scrapy_redis.spiders import RedisSpider
class DistributedMobileSpider(RedisSpider):
name = "distributed_mobile_spider"
redis_key = "mobile:start_urls"
def parse(self, response):
# 解析ロジックは通常のSpiderと似ています
pass
この設定では、redis_key
が Redis に保存される起始 URL のキーを指定します。起始 URL を Redis キューに入れることで、異なるクローラーノードがキューからタスクを取得して処理し、分散クローリングを実現します。
八、总结与展望#
今回のクローラーの旅では、基本構文から始まり、クローラーの核心原理、一般的なライブラリ、進階技術、フレームワークの応用、実践プロジェクトに至るまで段階的に深く掘り下げました。学習を通じて、Python 言語を利用してクローラー環境を構築し、さまざまなライブラリやツールを使用して HTTP リクエストを送信し、ウェブデータを解析し、反クローリングメカニズムを処理し、高効率なデータ収集を実現する方法を習得しました。また、異なるクローラーフレームワークの特徴や利点、実際のプロジェクトでの応用方法についても理解しました。
未来を展望すると、クローラー技術はインターネットの発展とともに進化し続けるでしょう。ビッグデータや人工知能技術の急成長に伴い、クローラー技術はデータ収集や分析の分野でより重要な役割を果たすことが期待されます。将来的には、クローラーはよりインテリジェントになり、ウェブページの構造の変化を自動的に認識し、柔軟に取得戦略を調整することで、データ収集の正確性と効率を向上させることができるでしょう。また、分散クローラーの分野では、技術の進歩に伴い、複数ノードの協力効率がさらに向上し、大規模なデータクローリングタスクをより迅速に処理できるようになるでしょう。さらに、データの安全性とプライバシー保護への意識が高まる中で、クローラー技術は合法性と安全性により重点を置き、合法的かつ安全な前提の下でデータ収集を行うことが求められるでしょう。
クローラー技術の発展の可能性は広がっており、無限の可能性に満ちています。皆さんが今後の学習や実践の中で、探求と革新を続け、クローラー技術の利点を最大限に発揮し、さまざまな分野の発展に貢献できることを願っています。