以前はクローラーを作成していましたが、最も使用されていたフレームワークはスクレイプでしたが、現在は新しくリリースされたクローラーフレームワークfeapderを使用してクローラーを開発し、それがどのようなエクスペリエンスであるかを確認しています。
ターゲットWebサイト:aHR0cHM6Ly93d3cubGFnb3UuY29tLw ==
要件:ジョブリストとジョブの詳細を収集し、詳細を7日ごとに更新する必要があります。
デモンストレーションのために、以下はクローラーに関連する投稿のみを検索します。
1.調査
1.1リストページ
まず、ページが動的にレンダリングされるかどうか、およびインターフェイスにクライミング防止機能があるかどうかを確認する必要があります。
動的レンダリングかどうかを確認するには、右クリックしてWebページのソースコードを表示し、Webページ上のコンテンツソースコードの存在を検索します。たとえば、検索リストの最初のZhiyiテクノロジーが一致する場合0、最初は動的レンダリングであると判断されます
または、feapderコマンドを使用して、Webページのソースコードをダウンロードして表示することもできます。
開いたページを読み込んでいます
response.open()コマンドを呼び出すと、作業ディレクトリにtemp.htmlファイルが生成されます。コンテンツは現在のリクエストによって返されたソースコードです。クリックして表示します。これは、セキュリティ検証が行われたjsのセクションです。したがって、ウェブサイトには登山防止とアップグレードの難しさの早期警告があると推測できます。
Feapderはcurlコマンドリクエストの使用もサポートしています。方法は次のとおりです。
F12キーを押すか、右クリックして確認し、デバッグウィンドウを開き、ページを更新し、現在のページのリクエストをクリックして、curlとしてコピーし、コマンドラインウィンドウに戻って、feapderシェルに入ります-コピーしたばかりのコンテンツを貼り付けます
ヘッダーとCookieの伝送は適切ではないことがわかりました。おそらく、一部のパラメーターは1回しか使用できません。
研究の結論:リストページでのクライミング防止、ページの動的レンダリング
ps:通常の神は、リストインターフェイスとは何か、アンチクロールをクラックする方法を調査し続けますが、私は初心者なので、心配する必要はありません。
1.2詳細ページ
リストページの調査と同様に、結論として、クロール防止機能はありますが、ページは動的にレンダリングされません。
2.プロジェクトを作成します
コマンドラインツールを開き、次のように入力します。
> feapder create -p lagou-spider
lagou-spider 项目生成成功
生成されたプロジェクトは次のとおりです。
私はpycharmを使用し、最初に右クリックして、このアイテムをワークスペースに追加します。
(プロジェクト名を右クリックし、ディレクトリを->ソースルートとしてマークします)
3.リストページクローラーを作成します
3.1クローラーを作成する
> cd lagou-spider/spiders
> feapder create -s list_spider
ListSpider 生成成功
生成されるコードは次のとおりです。
import feapder
class ListSpider(feapder.AirSpider):
def start_requests(self):
yield feapder.Request("https://www.baidu.com")
def parse(self, request, response):
print(response)
if __name__ == "__main__":
ListSpider().start()
これは、直接実行できるBaiduをリクエストする例です。
3.2 写爬虫
タスクの発行:
def start_requests(self):
yield feapder.Request("https://www.lagou.com/jobs/list_%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput=", render=True)
このリストページは動的にレンダリングされ、アンチクロールがあるため、レンダリングにブラウザを使用するかどうかを示すために、リクエストでrenderパラメータを実行したことに注意してください。かなり混乱しているため、脱毛を避けるためにレンダリングモードを使用しました。
分析関数を書く
ページ構造を観察し、次の分析関数を記述します
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
print(job_name, company, salary, job_url)
ジョブ名、会社、給与、およびジョブの詳細アドレスを解析しました。通常のロジックでは、詳細を取得するためのタスクとして詳細アドレスを送信する必要があります。
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
print(job_name, company, salary, job_url)
yield feapder.Request(
job_url, callback=self.parse_detail, cookies=response.cookies.get_dict()
) # 携带列表页返回的cookie,回调函数指向详情解析函数
def parse_detail(self, request, response):
print(response.text)
# TODO 解析详情
ただし、詳細は7日ごとに更新される必要があり、リストには更新が必要であるとは記載されていません。したがって、最適化するために、詳細用に別のクローラーを作成します。このクローラーは、次のタスクのみを担当します。リストのデータと制作の詳細。
多くの人がPythonを学び、どこから始めればよいのかわかりません。
多くの人がPythonを学び、基本的な文法を習得した後、どこから始めればよいかわかりません。
事例研究を行った多くの人々は、より高度な知識を学ぶ方法を知りません。
したがって、これら3つのタイプの人々のために、ビデオチュートリアル、電子書籍、およびコースのソースコードを無料で受け取ることができる優れた学習プラットフォームを提供します。
QQグループ:705933274
3.3データストレージ
テーブルを作成する
ジョブリストデータシートlagou_job_list
CREATE TABLE `lagou_job_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`job_name` varchar(255) DEFAULT NULL COMMENT '职位名称',
`company` varchar(255) DEFAULT NULL COMMENT '公司',
`salary` varchar(255) DEFAULT NULL COMMENT '薪资',
`job_url` varchar(255) DEFAULT NULL COMMENT '职位地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
詳細なタスクテーブルlagu_job_detail_task
CREATE TABLE `lagou_job_detail_task` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`state` int(11) DEFAULT '0' COMMENT '任务状态(0未做,1完成,2正在做,-1失败)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
データの保存方法
データをデータベースに保存する方法、pymysqlを直接インポートしてから、SQLステートメントをデータベースに接続する方法、またはフレームワークに付属のMysqlDBを使用する方法はたくさんあります。ただし、Feapderには、より便利な倉庫保管方法、自動倉庫保管があります。
自動保存AirSpiderは、それが比較的軽量であるため、サポートされていません。軽量な機能を維持するために、著者は、当面の自動ストレージをサポートしていません。ただし、分散クローラーSpiderはサポートされているため、Spiderではなくクラスを直接統合します。
class ListSpider(feapder.AirSpider):
に
class ListSpider(feapder.Spider):
アイテムを生成する
この項目は、テーブルに1つずつ対応し、データストレージメカニズムに関連しており、feapderコマンドで生成できます。
まず、設定で構成されているデータベース接続情報を構成します
アイテムの生成:
> cd items
> feapder create -i lagou_job_list
> feapder create -i lagou_job_detail_task
データストレージ
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
# 列表数据
list_item = lagou_job_list_item.LagouJobListItem()
list_item.job_name = job_name
list_item.company = company
list_item.salary = salary
list_item.job_url = job_url
yield list_item # 直接返回,框架实现批量入库
# 详情任务
detail_task_item = lagou_job_detail_task_item.LagouJobDetailTaskItem()
detail_task_item.url = job_url
yield detail_task_item # 直接返回,框架实现批量入库
データはyieldアイテムの形式でフレームワークに返され、フレームワークは自動的にバッチで保存されます。
3.4全体的なコード
import feapder
from items import *
class ListSpider(feapder.Spider):
def start_requests(self):
yield feapder.Request(
"https://www.lagou.com/jobs/list_%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput=",
render=True,
)
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
# 列表数据
list_item = lagou_job_list_item.LagouJobListItem()
list_item.job_name = job_name
list_item.company = company
list_item.salary = salary
list_item.job_url = job_url
yield list_item # 直接返回,框架实现批量入库
# 详情任务
detail_task_item = lagou_job_detail_task_item.LagouJobDetailTaskItem()
detail_task_item.url = job_url
yield detail_task_item # 直接返回,框架实现批量入库
if __name__ == "__main__":
spider = ListSpider(redis_key="feapder:lagou_list")
spider.start()
redis_keyは、タスクキューがredisに保存される場所です。
直接実行して、データがデータベースに自動的に保存されていることを確認します
4.詳細クローラーを書く
リストページクローラーとは異なり、詳細データは7日ごとに更新する必要があります。
時系列データを表示するために、7日ごとにデータを収集します。データはバッチ情報を伝達し、7日ディメンションに従ってデータを分割する必要があります。
feapderフレームワークに接続する前に、詳細なタスクテーブルからクローラーにタスクをバッチで取得することを検討する必要があります。また、タスクのステータスと上記のバッチ情報を維持する必要があります。また、データの適時性を確保するためには、収集の進行状況を監視する必要があり、クローラーの作成は非常に面倒です。
では、Feapderはどのように機能しますか?スペースを節約するために、完全なコードを直接提供してください。
import feapder
from items import *
class DetailSpider(feapder.BatchSpider):
def start_requests(self, task):
task_id, url = task
yield feapder.Request(url, task_id=task_id, render=True)
def parse(self, request, response):
job_name = response.xpath('//div[@class="job-name"]/@title').extract_first().strip()
detail = response.xpath('string(//div[@class="job-detail"])').extract_first().strip()
item = lagou_job_detail_item.LagouJobDetailItem()
item.title = job_name
item.detail = detail
item.batch_date = self.batch_date # 获取批次信息,批次信息框架自己维护
yield item # 自动批量入库
yield self.update_task_batch(request.task_id, 1) # 更新任务状态
if __name__ == "__main__":
spider = DetailSpider(
redis_key="feapder:lagou_detail", # redis中存放任务等信息的根key
task_table="lagou_job_detail_task", # mysql中的任务表
task_keys=["id", "url"], # 需要获取任务表里的字段名,可添加多个
task_state="state", # mysql中任务状态字段
batch_record_table="lagou_detail_batch_record", # mysql中的批次记录表
batch_name="详情爬虫(周全)", # 批次名字
batch_interval=7, # 批次周期 天为单位 若为小时 可写 1 / 24
)
# 下面两个启动函数 相当于 master、worker。需要分开运行
# spider.start_monitor_task() # 下发及监控任务
spider.start() # 采集
spider.start_monitor_task()とspider.start()をそれぞれ実行し、クローラーが終了した後、データベースを監視します
タスクテーブル:lagu_job_detail_task
すべてのタスクが完了しました。フレームワークには、タスクが欠落した後、すべてのタスクが完了するまでタスクを再送信するメカニズムがあります。
データシート:lagu_job_detail:
データにはバッチ時間情報が含まれており、この時間に応じてデータを分割できます。現在のバッチは3月19日です。バッチが7日以内に発生した場合、次のバッチは3月26日になります。
このバッチ中にクローラーを繰り返し起動します。新しいタスクがない場合、クローラーは
spider.start_monitor_task()を取得しません。
spider.start()
バッチテーブル:lagu_detail_batch_record
バッチテーブルは起動パラメータで指定され、自動的に生成されます。バッチテーブルには、タスクの合計量、実行された量、失敗の量、完了したかどうか、その他の情報など、各バッチのキャプチャステータスが詳細に記録されます。
5.統合
現在、リストクローラーと詳細クローラーの両方が書き込まれています。実行中のエントリは2つのファイルに分散されているため、管理が面倒です。Feapderではmain.pyに書き込むことをお勧めします。
from feapder import ArgumentParser
from spiders import *
def crawl_list():
"""
列表爬虫
"""
spider = list_spider.ListSpider(redis_key="feapder:lagou_list")
spider.start()
def crawl_detail(args):
"""
详情爬虫
@param args: 1 / 2 / init
"""
spider = detail_spider.DetailSpider(
redis_key="feapder:lagou_detail", # redis中存放任务等信息的根key
task_table="lagou_job_detail_task", # mysql中的任务表
task_keys=["id", "url"], # 需要获取任务表里的字段名,可添加多个
task_state="state", # mysql中任务状态字段
batch_record_table="lagou_detail_batch_record", # mysql中的批次记录表
batch_name="详情爬虫(周全)", # 批次名字
batch_interval=7, # 批次周期 天为单位 若为小时 可写 1 / 24
)
if args == 1:
spider.start_monitor_task()
elif args == 2:
spider.start()
if __name__ == "__main__":
parser = ArgumentParser(description="xxx爬虫")
parser.add_argument(
"--crawl_list", action="store_true", help="列表爬虫", function=crawl_list
)
parser.add_argument(
"--crawl_detail", type=int, nargs=1, help="详情爬虫(1|2)", function=crawl_detail
)
parser.start()
開始コマンドを表示します。
> python3 main.py --help
usage: main.py [-h] [--crawl_list] [--crawl_detail CRAWL_DETAIL]
xxx爬虫
optional arguments:
-h, --help show this help message and exit
--crawl_list 列表爬虫
--crawl_detail CRAWL_DETAIL
详情爬虫(1|2)
リストクローラーを開始します。
python3 main.py --crawl_list
詳細なクローラーマスターを起動します
python3 main.py --crawl_detail 1
詳細なクローラーワーカーを開始します
python3 main.py --crawl_detail 2
総括する
この記事では、求人サイトを例として取り上げ、feapderを使用してデータを収集するプロセス全体を紹介します。これには、AirSpider、Spider、BatchSpiderの3つのクローラーの使用が含まれます。
- AirSpiderクローラーは比較的軽量で、学習コストが低くなっています。データ量が少なく、ブレークポイントなしでクロールを続行する必要がなく、分散収集も必要ない場合は、このクローラーを使用できます。
- Spiderは、redisに基づく分散クローラーであり、大量のデータ収集に適しており、ブレークポイントでの継続的なクロール、クローラーアラーム、自動データストレージなどの機能をサポートします。
- BatchSpiderは分散バッチクローラーです。定期的に収集する必要があるデータについては、このクローラーが優先されます。
ブラウザのレンダリングとダウンロードをサポートすることに加えて、feapderはパイプラインもサポートします。パイプラインは、他のデータベースとのドッキングを容易にするためにユーザーがカスタマイズできます。
豊富なアラームがフレームワークに組み込まれており、データの適時性を確保するために、クローラーに問題が発生したときに通知されます
- クローラーのクロール速度をリアルタイムで計算し、残り時間を見積もり、指定されたクロールサイクル内でタイムアウトするかどうかを予測します
- 爬虫類のスタックアラーム
- クローラータスクの失敗アラームが多すぎます。これは、Webサイトテンプレートの変更またはブロックが原因である可能性があります
- ダウンロードステータスモニタリング