shiqi

shiqi

Study GIS, apply to world
twitter
github
bento
jike

Python クローラー

一、爬虫初印象#

image

インターネットの広大な世界では、データは宝物のように至る所に散らばっています。そして、クローラーは特定のルールに従って自動的にウェブページを行き来し、私たちが必要とする情報を取得できる勤勉な宝探し者のようです。簡単に言えば、これはウェブデータを自動的に取得するプログラムまたはスクリプトであり、正式名称はウェブクローラー(Web Crawler)で、ウェブスパイダーやネットワークロボットとも呼ばれます。

クローラーはデータ取得において重要な役割を果たしています。現在、データは企業や研究者の意思決定の重要な根拠となっており、クローラーは大量のデータを取得するための効率的な手段です。その応用シーンは非常に広範で、データ分析の分野では、クローラーを使用してソーシャルメディアプラットフォーム上のユーザーコメントや行動データを収集することで、企業がユーザーのニーズや市場のトレンドを正確に洞察し、製品の最適化やマーケティング戦略の策定に強力な支援を提供します。競合調査においては、クローラーが競合他社の製品情報、価格動向、プロモーション活動などを定期的に取得し、企業が迅速に戦略を調整し、競争力を維持するのに役立ちます。さらに、学術研究やニュース情報の集約などの分野でも、クローラーは不可欠な役割を果たしています。

二、環境搭建与基础语法#

2.1 Python 安装与配置#

Python はクローラー開発の第一選択言語であり、そのシンプルな構文と豊富なライブラリは開発プロセスを大幅に簡素化します。まず、Python 公式ウェブサイト(https://www.python.org/downloads/)から、あなたのオペレーティングシステムに適したインストーラをダウンロードする必要があります。ダウンロードページでは、さまざまなバージョンの Python が表示され、最新の安定版を選択することをお勧めします。ダウンロードが完了したら、インストーラを実行し、インストールウィザードで「Add Python to PATH」オプションを必ずチェックしてください。このステップは非常に重要で、Python がシステムの任意のパスから呼び出されることを保証します。

インストールが完了したら、コマンドプロンプト(CMD)でpython --versionと入力して、インストールが成功したかどうかを確認できます。成功した場合、Python のバージョン情報が表示されます。また、pythonと入力して Python インタラクティブ環境に入ることもでき、ここで直接 Python コードを記述して実行し、Python の魅力を体験できます。

2.2 开发工具选择#

良い開発ツールは開発効率を大幅に向上させることができます。クローラー開発において、PyCharm は非常に人気のある統合開発環境(IDE)です。強力なコード編集機能を備えており、コードの自動補完、構文ハイライト、コードナビゲーションなどが可能で、コードを書く際によりスムーズに作業できます。同時に、PyCharm は Python のさまざまなライブラリやフレームワークを良好にサポートし、プロジェクト管理やデバッグを容易にします。

PyCharm の他にも、Visual Studio Code(VS Code)などの優れた選択肢があります。これは軽量でありながら強力なコードエディタで、Python プラグインをインストールすることで効率的な Python 開発が可能です。VS Code は優れた拡張性とクロスプラットフォーム性を持ち、シンプルな開発環境を好む開発者に適しています。

2.3 Python 基础语法回顾#

正式にクローラー開発を始める前に、Python の基本構文を振り返ることは非常に重要です。これにはデータ型、制御文、関数などが含まれます。

Python にはさまざまな基本データ型があります。例えば、整数(int)、浮動小数点数(float)、文字列(str)、ブール値(bool)などです。異なるデータ型はデータを保存し操作する際にそれぞれ特徴があります。例えば、文字列はテキスト情報を保存するために使用され、インデックスやスライス操作を通じて文字列内の特定の文字や部分文字列を取得できます。サンプルコードは以下の通りです:

name = "クローラーの達人"

print(name[0])  # 最初の文字を出力

print(name[2:5])  # 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を出力

これらの基本構文を習得することで、今後のクローラー開発のための堅固な基盤を築くことができます。

三、爬虫基础原理与流程#

image

3.1 HTTP 协议解析#

HTTP プロトコル、すなわちハイパーテキスト転送プロトコルは、クローラーとウェブサーバー間の通信の基礎です。これはクローラーとサーバー間の共通言語のようなもので、双方がどのようにデータを要求し、転送するかを規定しています。

HTTP リクエストは主にリクエストライン、リクエストヘッダー、リクエストボディ(オプション)で構成されています。リクエストラインにはリクエストメソッド、URL、HTTP バージョンが含まれます。一般的なリクエストメソッドには GET と POST があります。GET メソッドは通常、サーバーからリソースを取得するために使用されます。例えば、ウェブページにアクセスする際、ブラウザはサーバーに GET リクエストを送信し、ウェブページの HTML コンテンツを取得します。GET リクエストを使用する際、パラメータは URL の末尾に付加され、キーと値のペアの形式で表示されます。例えば、https://example.com/search?q=クローラー&page=1のように、パラメータが URL に表示されるため、機密情報の送信にはあまり適していません。

POST メソッドは、サーバーにデータを送信するために一般的に使用されます。例えば、ログインフォームやコメントの送信などの操作です。GET とは異なり、POST リクエストのパラメータはリクエストボディに配置され、ユーザーには見えず、安全性が相対的に高くなります。例えば、ログイン時にユーザー名とパスワードが POST リクエストを通じてサーバーに送信され、リクエストボディにはusername=admin&password=123456のような内容が含まれる可能性があります。

HTTP レスポンスは、ステータスライン、レスポンスヘッダー、レスポンスボディで構成されています。ステータスラインのステータスコードは、リクエストの処理結果を直感的に反映します。例えば、200 はリクエストが成功し、サーバーが要求されたリソースを正常に返したことを示します。404 は要求されたリソースが存在しないことを示し、URL の入力ミスやページが削除された可能性があります。500 はサーバー内部でエラーが発生したことを示します。レスポンスヘッダーには、レスポンスに関するメタ情報が含まれています。例えば、コンテンツタイプ(text/htmlは HTML ページが返されることを示します)、コンテンツの長さなどです。レスポンスボディは、私たちが本当に取得したいデータ、例えばウェブページの HTML コードや JSON 形式のデータなどです。

3.2 爬虫工作流程#

クローラーの作業フローは、リクエストの発行、レスポンスの取得、データの解析、データの保存といういくつかの重要なステップに要約できます。

まず、クローラーは設定された URL に基づいて、HTTP ライブラリ(Python のrequestsライブラリなど)を使用してターゲットサーバーにリクエストを発行します。この過程で、実際のユーザーのアクセスを模倣するために、リクエストヘッダーを設定することがあります。例えば、User-Agentを設定することで、サーバーに訪問者が使用しているブラウザの種類やオペレーティングシステムなどの情報を伝えることができます。以下のコードは、requestsライブラリを使用して GET リクエストを発行する例です:

import requests

url = "https://example.com"

headers = {

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

}

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

サーバーがリクエストを受信すると、適切なレスポンスを返します。リクエストが成功した場合、ステータスコード、レスポンスヘッダー、レスポンスボディを含むレスポンスオブジェクトが得られます。クローラーはレスポンスを取得した後、次にレスポンスボディから必要なデータを抽出します。このステップでは、データの形式に応じて適切な解析方法を選択する必要があります。レスポンスボディが HTML 形式の場合、BeautifulSouplxmlなどのライブラリを使用して解析できます。例えば、BeautifulSoupを使用して HTML ページを解析し、すべてのリンクを抽出する場合:

from bs4 import BeautifulSoup

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

links = soup.find_all('a')

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

レスポンスボディが JSON 形式のデータである場合、Python の組み込みjsonモジュールを使用して解析できます。以下はその例です:

import json

data = json.loads(response.text)

print(data)

最後に、解析したデータをローカルファイルやデータベースに保存し、後で分析や使用できるようにします。ファイルに保存する一般的な形式には、テキストファイル(.txt)、CSV ファイル(.csv)、JSON ファイル(.json)などがあります。例えば、データを JSON ファイルとして保存する場合:

import json

data = [{"name": "クローラー", "info": "データ収集ツール"}]

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

データベースに保存する必要がある場合、リレーショナルデータベース(MySQL など)にはpymysqlライブラリを使用し、非リレーショナルデータベース(MongoDB など)にはpymongoライブラリを使用できます。

四、爬虫常用库实战#

image

4.1 Requests 库#

Requests ライブラリは Python で HTTP リクエストを送信するための強力なツールであり、その API はシンプルで明確で、ウェブサーバーとのインタラクションを簡単にします。Requests ライブラリを使用する際は、まずインストールされていることを確認し、pip install requestsコマンドでインストールできます。

インストールが完了したら、コード内で使用できます。例えば、ウェブページの内容を取得するためにシンプルな GET リクエストを送信する場合:

import requests

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

response = requests.get(url)

if response.status_code == 200:

      print(response.text)

else:

      print(f"リクエスト失敗、ステータスコード: {response.status_code}")

この例では、requests.get(url)が指定された URL に GET リクエストを送信し、レスポンスオブジェクトresponseを返します。response.status_codeをチェックすることで、リクエストが成功したかどうかを判断できます。ステータスコードが 200 であれば、リクエストが成功し、response.textにはウェブページの HTML 内容が含まれています。

GET リクエストの他に、Requests ライブラリは POST リクエストもサポートしており、サーバーにデータを送信するために使用されます。例えば、ログインフォームの送信を模倣する場合:

import requests

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

data = {

      "username": "your_username",

      "password": "your_password"

}

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

print(response.text)

このコードでは、data辞書にログインに必要なユーザー名とパスワードが含まれ、requests.post(url, data=data)がこれらのデータを指定されたログイン URL に送信します。

また、リクエストヘッダーを設定して異なるブラウザのアクセスを模倣したり、レスポンスの JSON データを処理したり、リクエストのタイムアウトを設定したりすることもできます。例えば、リクエストヘッダーを設定する場合:

import requests

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

headers = {

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

}

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

print(response.text)

この例では、headers辞書がUser-Agentを設定し、サーバーに私たちが Chrome ブラウザを使用していることを伝えます。これにより、一部のウェブサイトが非ブラウザのアクセスを検出してリクエストを拒否するのを避けることができます。

4.2 BeautifulSoup 库#

BeautifulSoup ライブラリは、HTML および XML データを解析するための強力なツールです。複雑な HTML または XML ドキュメントを簡単に遍歴および操作できるツリー構造に変換し、必要なデータを簡単に抽出できます。BeautifulSoup ライブラリを使用する前に、pip install beautifulsoup4コマンドでインストールする必要があります。

Requests ライブラリを使用してウェブページの HTML 内容を取得したと仮定し、次に BeautifulSoup ライブラリを使用して解析します。例えば:

from bs4 import BeautifulSoup

import requests

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

response = requests.get(url)

if response.status_code == 200:

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

      # すべてのリンクを抽出

      links = soup.find_all('a')

      for link in links:

          print(link.get('href'))

else:

      print(f"リクエスト失敗、ステータスコード: {response.status_code}")

このコードでは、BeautifulSoup(response.text, 'html.parser')が取得した HTML 内容をBeautifulSoupオブジェクト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 内容をlxmlElementオブジェクト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"]がクラス属性値が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 つ以上の文字が続くことを示します。この正規表現パターンは、一般的な電子メールアドレス形式を正確にマッチさせることができます。

五、爬虫进阶技巧#

image

5.1 处理反爬虫机制#

クローラーの旅の中で、私たちはしばしばウェブサイトの反クローラー機構に遭遇します。これはまるで宝探しの道中に多くの障害があるかのようです。しかし心配しないでください、私たちには一連の効果的な対策があります。

リクエストヘッダーを設定することは、シンプルで効果的な方法です。ウェブサイトはしばしばリクエストヘッダー内のUser-Agentなどの情報を検出して、リクエストがクローラーから来ているかどうかを判断します。私たちは実際のブラウザのリクエストヘッダーを模倣することで、ウェブサイトに普通のユーザーがアクセスしていると誤認させることができます。例えば、Python のrequestsライブラリでリクエストヘッダーを設定する場合:

import requests

url = "https://example.com"

headers = {

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

}

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

ここでのUser-Agent文字列は Chrome ブラウザの情報を模倣しており、この方法でリクエストの信頼性を高めることができます。

プロキシ IP を使用することも、反クローラー制限を突破するための重要な手段です。私たちの IP アドレスが頻繁なリクエストのためにウェブサイトに禁止された場合、プロキシ IP は私たちの「代わり」となり、ウェブサイトへのアクセスを続けるのを助けます。無料または有料のプロキシ IP サービスを使用することができ、Python ではrequestsライブラリを使用してプロキシ IP を設定する例は以下の通りです:

import requests

url = "https://example.com"

proxies = {

      "http": "http://your_proxy_ip:your_proxy_port",

      "https": "https://your_proxy_ip:your_proxy_port"

}

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

プロキシ IP を使用する際は、信頼できるプロキシソースを選択し、プロキシ IP の安定性と可用性を確保することが重要です。

さらに、リクエストの頻度を制御することも非常に重要です。短時間にウェブサイトに大量のリクエストを送信すると、クローラーとして認識されやすくなります。私たちは時間間隔を設定することで、リクエストをより「穏やか」にすることができます。例えば、timeモジュールのsleep関数を使用して、各リクエストの後に一定の時間を一時停止させる場合:

import requests

import time

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

for url in url_list:

      response = requests.get(url)

      time.sleep(5)  # 5秒間一時停止

こうすることで、5 秒ごとにリクエストを送信し、反クローラー機構に検出されるリスクを低減します。

5.2 动态网页抓取#

ウェブ技術の発展に伴い、ますます多くのウェブページが動的読み込み技術を採用しており、これがクローラーに新たな課題をもたらしています。従来の HTML 内容を直接取得する方法では、動的に読み込まれるデータを取得できない場合があります。しかし、私たちにはこの状況に対処するための特別なツールがあります。

Selenium は強力な自動化テストツールで、実際のユーザーがブラウザ内で操作するのを模倣することで、動的ウェブページの完全な内容を取得できます。Selenium を使用するには、まず対応するブラウザドライバをインストールする必要があります。Chrome ブラウザの場合、ChromeDriver のウェブサイトからブラウザバージョンに一致するドライバをダウンロードします。インストールが完了したら、pip install seleniumで Selenium ライブラリをインストールします。以下は Selenium を使用してウェブページを開き、内容を取得する例です:

from selenium import webdriver

driver = webdriver.Chrome()

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

# ウェブページの内容を取得

page_source = driver.page_source

print(page_source)

driver.quit()

この例では、webdriver.Chrome()が Chrome ブラウザドライバのインスタンスを作成し、driver.get(url)が指定されたウェブページを開き、driver.page_sourceがウェブページのソースコードを取得し、最後にdriver.quit()がブラウザを閉じます。

Selenium の他にも、Scrapy - Splash は良い選択肢です。これは Scrapy フレームワークのプラグインで、動的ウェブページを処理するために特化しています。Splash は JavaScript レンダリングに基づくサービスで、サーバー側で JavaScript をレンダリングし、レンダリングされた HTML をクローラーに返します。Scrapy - Splash を使用するには、まず Splash サービスをインストールし、Scrapy プロジェクトで適切な設定を行います。設定が完了したら、クローラーコード内で Splash を使用して動的ウェブページを処理できます。例えば、Scrapy のsettings.pyファイルに次の設定を追加します:

SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {

    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,

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

    'scrapy_splash.SplashMiddleware': 820,

}

SPIDER_MIDDLEWARES = {

    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,

    'scrapy_splash.SplashSpiderMiddleware': 725,

}

DUPEFILTER_CLASS ='scrapy_splash.SplashAwareDupeFilter'

HTTPCACHE_STORAGE ='scrapy_splash.SplashAwareFSCacheStorage'

次に、クローラーコード内で Splash のRequestオブジェクトを使用してリクエストを送信します:

from scrapy_splash import SplashRequest

class MySpider(scrapy.Spider):

      name = "my_spider"

      start_urls = ["https://example.com"]

      def start_requests(self):

          for url in self.start_urls:

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

      def parse(self, response):

          # ウェブページの内容を解析

          pass

この例では、SplashRequestがリクエストを Splash サービスに送信し、args={'wait': 5}はページの 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)がこれらのタスクを並行して実行し、すべてのタスクが完了するのを待ちます。この方法で、高効率な非同期クローラーを実現しています。

六、爬虫框架应用#

image

6.1 Scrapy 框架#

Scrapy は強力で広く使用されている Python クローラーフレームワークであり、クローラー開発に高効率で便利なソリューションを提供します。

Scrapy のアーキテクチャは、精密な機械のようで、複数のコアコンポーネントが協調して動作します。その中で、エンジン(Engine)はフレームワーク全体の中心的なハブであり、各コンポーネント間の通信とデータの流れを調整します。エンジンはスケジューラ(Scheduler)からクローリングする URL を取得し、リクエストをダウンローダー(Downloader)に送信します。ダウンローダーはネットワークからウェブページの内容をダウンロードし、レスポンスをエンジンに返します。エンジンはレスポンスをクローラー(Spider)に渡してデータ解析を行います。パイプライン(Pipeline)はクローラーが抽出したデータを処理し、データのクレンジングや保存などの操作を行います。スケジューラはインテリジェントなタスク配分器のようで、URL キューを維持し、クローリングする URL を管理およびスケジュールし、各 URL が合理的にクローリング順序を安排されるようにし、重複する URL を除去することもできます。

Scrapy フレームワークを使用する際は、まず Scrapy プロジェクトを作成する必要があります。コマンドラインでscrapy startproject プロジェクト名と入力することで、迅速にプロジェクトフレームワークを作成できます。例えば、my_crawlerという名前のプロジェクトを作成する場合、コマンドは以下の通りです:

scrapy startproject my_crawler

プロジェクトディレクトリに入った後、scrapy genspider クローラー名 目標ドメイン名コマンドを使用してクローラーを作成できます。例えば、example.comウェブサイトのデータをクローリングする場合、クローラーを作成するコマンドは以下の通りです:

cd my_crawler

scrapy genspider example_spider example.com

生成されたクローラーファイル内で、クローラーのロジックを定義する必要があります。例えば、以下は指定されたウェブページのタイトル情報をクローリングするためのシンプルなクローラーの例です:

import scrapy

class ExampleSpider(scrapy.Spider):

      name = "example_spider"

      allowed_domains = ["example.com"]

      start_urls = ["https://example.com"]

      def parse(self, response):

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

          for title in titles:

              yield {'title': title}

この例では、parseメソッドがクローラーのコアロジック部分であり、CSS セレクタを使用してウェブページ内のタイトル情報を抽出し、yieldを通じてデータをパイプラインに渡して後続処理を行います。

6.2 PySpider 框架#

PySpider は軽量でありながら強力なクローラーフレームワークで、独特の特徴と適用シーンを持っています。

PySpider の大きな特徴は、その直感的で使いやすい WebUI インターフェースを提供していることです。このインターフェースを通じて、開発者はプロジェクト管理、タスクモニタリング、結果の確認を簡単に行うことができます。WebUI では、クローラータスクを簡単に作成、編集、起動し、クローラーの実行状態をリアルタイムで把握し、収集したデータ結果を確認することができ、開発とデバッグの効率が大幅に向上します。

PySpider は、MySQL、MongoDB、Redis などの一般的なデータストレージ方式をサポートしています。これにより、開発者はプロジェクトの実際のニーズに応じて最適なデータストレージソリューションを柔軟に選択し、後続のデータ処理や分析を容易に行うことができます。

また、強力な分散クローラー機能も備えています。複数のクローラーノードを設定することで、PySpider は高い同時実行性のクローリングタスクを実現し、データ収集の速度と効率を大幅に向上させます。この特性により、大規模なデータクローリングタスクを処理する際に優れたパフォーマンスを発揮します。

例えば、PySpider を使用してニュースサイトの文章内容をクローリングする場合、まず PySpider をインストールします。pip install pyspiderコマンドでインストールできます。インストールが完了したら、PySpider サービスを起動し、pyspider allコマンドを入力します。ブラウザでhttp://localhost:5000にアクセスし、PySpider の WebUI インターフェースに入ります。WebUI で新しいクローラープロジェクトを作成し、以下のクローラーコードを記述します:

from pyspider.libs.base_handler import *

class NewsSpider(BaseHandler):

      crawl_config = {}

      @every(minutes=24 * 60)

      def on_start(self):

          self.crawl('https://news.example.com', callback=self.index_page)

      def index_page(self, response):

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

              self.crawl(each.attr.href, callback=self.detail_page)

      def detail_page(self, response):

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

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

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

この例では、on_startメソッドがクローラーの開始 URL を定義し、index_pageメソッドがリストページを解析し、記事リンクを抽出してdetail_pageメソッドに渡して詳細ページを解析し、最終的に記事のタイトルと内容を抽出します。PySpider の WebUI インターフェースを通じて、このクローラータスクを簡単に起動、監視、管理できます。

七、实战项目演练#

image

7.1 小型爬虫项目#

皆さんにクローラーの魅力をより直感的に感じてもらうために、豆瓣映画 Top250 をクローリングする例を挙げて、完全なクローラー実装プロセスを示します。豆瓣映画 Top250 は映画愛好者が注目する人気ランキングで、豊富な映画情報が含まれています。

まず、ウェブページの構造を分析する必要があります。ブラウザの開発者ツール(例えば Chrome ブラウザの F12 ショートカットキー)を使用して、ウェブページの HTML ソースコードを確認し、映画情報が存在するタグや属性を見つけます。例えば、映画のタイトルは通常<span class="title">タグ内にあり、評価は<span class="rating_num">タグ内にあります。

次に、クローラーコードを記述します。Python のrequestsライブラリとBeautifulSoupライブラリを使用して、コードは以下の通りです:

import requests

from bs4 import BeautifulSoup

import csv

def get_movie_info(url):

      headers = {

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

      }

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

      if response.status_code == 200:

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

          movie_list = soup.find_all('div', class_='item')

          for movie in movie_list:

              title = movie.find('span', class_='title').text

              rating = movie.find('span', class_='rating_num').text

              quote = movie.find('span', class_='inq')

              quote = quote.text if quote else '無'

              yield {

                  'title': title,

                  'rating': rating,

                  'quote': quote

              }

      else:

          print(f"リクエスト失敗、ステータスコード: {response.status_code}")

def save_to_csv(data, filename='douban_movies.csv'):

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

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

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

          writer.writeheader()

          for movie in data:

              writer.writerow(movie)

if __name__ == "__main__":

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

      all_movie_info = []

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

          url = base_url.format(start)

          movie_info = get_movie_info(url)

          all_movie_info.extend(movie_info)

      save_to_csv(all_movie_info)

このコードでは、get_movie_info関数がリクエストを送信し、ウェブページを解析して映画のタイトル、評価、引用情報を抽出します。save_to_csv関数は抽出したデータを CSV ファイルとして保存します。異なるページ番号をループして、豆瓣映画 Top250 のすべての情報を取得できます。

7.2 大型综合爬虫项目#

次に、より挑戦的なタスクに進み、e コマースプラットフォームの製品情報をクローリングし、データの永続化と分散クローラー機能を実現します。特定の e コマースプラットフォームのスマートフォン製品情報をクローリングする例では、複数の複雑なステップが含まれます。

まず、反クローラー問題を解決する必要があります。e コマースプラットフォームは通常、厳格な反クローラー機構を持っており、リクエストヘッダーを設定したり、プロキシ IP を使用したりしてリクエストを偽装します。同時に、データの永続化を実現するために、データを MySQL データベースに保存することを選択します。以下はScrapyフレームワークを使用して実装した部分コードの例です:

import scrapy

import pymysql

class MobileSpider(scrapy.Spider):

      name = "mobile_spider"

      allowed_domains = ["example.com"]

      start_urls = ["https://example.com/mobiles"]

      def parse(self, response):

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

              item = {

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

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

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

              }

              yield item

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

          if next_page:

              yield response.follow(next_page, self.parse)

class MySQLPipeline:

      def __init__(self):

          self.conn = pymysql.connect(

              host='localhost',

              user='root',

              password='password',

              db='ecommerce',

              charset='utf8'

          )

          self.cursor = self.conn.cursor()

      def process_item(self, item, spider):

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

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

          self.cursor.execute(sql, values)

          self.conn.commit()

          return item

      def close_spider(self, spider):

          self.cursor.close()

          self.conn.close()

このコードでは、MobileSpiderクラスがクローラーのロジックを定義し、開始 URL、データ解析、ページネーション処理を行います。MySQLPipelineクラスは、クローリングしたデータを MySQL データベースのmobilesテーブルに挿入する役割を果たします。

分散クローラーについては、Scrapy - Redisフレームワークを利用して実現できます。Scrapy - Redisはクローリングタスクを複数のノードに分配して並行実行し、クローリング効率を大幅に向上させます。まず、Scrapy - Redisライブラリをインストールし、pip install scrapy-redisコマンドでインストールします。次に、settings.pyファイルで以下の設定を行います:

# Redisを使用してリクエストキューを保存するスケジューラを有効にする

SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# すべてのクローラーが同じ重複フィンガープリンターを共有することを保証する

DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# Redis接続設定

REDIS_HOST = 'localhost'

REDIS_PORT = 6379

クローラークラス内で、RedisSpiderクラスを継承します。以下のように:

from scrapy_redis.spiders import RedisSpider

class DistributedMobileSpider(RedisSpider):

      name = "distributed_mobile_spider"

      redis_key = "mobile:start_urls"

      def parse(self, response):

          # 解析ロジックは通常のSpiderと似ています

          pass

この設定では、redis_keyが Redis 内に保存される開始 URL のキーを指定します。開始 URL を Redis キューに入れることで、異なるクローラーノードがキューからタスクを取得して処理し、分散クローリングを実現します。

八、总结与展望#

image

今回のクローラーの旅では、基本構文から始まり、クローラーの核心原理、一般的なライブラリ、進階技術、フレームワークの応用、実践プロジェクトに至るまで段階的に深く掘り下げました。学習を通じて、Python 言語を利用してクローラー環境を構築し、さまざまなライブラリやツールを使用して HTTP リクエストを送信し、ウェブデータを解析し、反クローラー機構を処理し、高効率なデータ収集を実現する方法を習得しました。また、異なるクローラーフレームワークの特徴と利点を理解し、それを実際のプロジェクトに応用する方法も学びました。

未来を展望すると、クローラー技術はインターネットの発展とともに進化し続けるでしょう。ビッグデータや人工知能技術の急成長に伴い、クローラー技術はデータ収集と分析においてより重要な役割を果たすことが期待されます。将来的には、クローラーはよりインテリジェントになり、ウェブページ構造の変化を自動的に認識し、柔軟に取得戦略を調整することで、データ収集の正確性と効率を向上させることができるでしょう。また、分散クローラーの分野では、技術の不断の改善により、複数ノードの協力効率がさらに向上し、大規模なデータクローリングタスクをより迅速に処理できるようになるでしょう。さらに、データセキュリティとプライバシー保護の意識が高まる中で、クローラー技術は合法性と安全性により重点を置き、合法的かつ安全な前提の下でデータ収集を行うことが求められます。

クローラー技術の発展の可能性は広大であり、無限の可能性に満ちています。皆さんが今後の学習や実践の中で、探求と革新を続け、クローラー技術の利点を最大限に発揮し、さまざまな分野の発展に貢献できることを願っています。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。