【Scrapy初心者】連番収集の仕組み
スクレイピングするものは、ページ単体だけでなく、複数ページにまたがるのがほとんどだと思う。今回は、複数ページ、連番をどう収集するか?を考えてみます。
ここに記載されているソースで考えていきます。
import scrapy
from ten_min_scrapy.items import Post
class ScrapyBlogSpiderSpider(scrapy.Spider):
name = 'scrapy_blog_spider'
allowed_domains = ['blog.scrapinghub.com']
start_urls = ['http://blog.scrapinghub.com']
def parse(self, response):
"""
レスポンスに対するパース処理
"""
# response.css で scrapy デフォルトの css セレクタを利用できる
for post in response.css('.post-listing .post-item'):
# items に定義した Post のオブジェクトを生成して次の処理へ渡す
yield Post(
url=post.css('div.post-header a::attr(href)').extract_first().strip(),
title=post.css('div.post-header a::text').extract_first().strip(),
date=post.css('div.post-header span.date a::text').extract_first().strip(),
)
# 再帰的にページングを辿るための処理
older_post_link = response.css('.blog-pagination a.next-posts-link::attr(href)').extract_first()
if older_post_link is None:
# リンクが取得できなかった場合は最後のページなので処理を終了
return
# URLが相対パスだった場合に絶対パスに変換する
older_post_link = response.urljoin(older_post_link)
# 次のページをのリクエストを実行する
yield scrapy.Request(older_post_link, callback=self.parse)
実行するファイルはこちら。
Spiderファイルの全体の構造は?
全体の構造として、
上部にアクセスするURLが記載しており、
次に、parse()
CSSセクレタを使って URL,title、dataを取得を繰り返す。
それが終わると。
リンクがあるか?を確認してできなければ、そこで終了。
リンクがあるとコールバックをする。
is None と == None の違い
if文だと普通は ==で指定するとおもってましたが、「is」がつかわれてます。まずは、Noneについて
if older_post_link is None:
Noneは、「nullオブジェクト」で、かんたんに言えば「空っぽのオブジェクト」。そして、「older_post_link」がNoneのときに、「True」を返す。
returndeで、呼び出し元にそのデータを返すのだが、何も無いを返して終了。
参考:PythonではNoneの比較は==ではなくisを使う
==だとエラーになる可能性がる、あと判別が早い。とのこと。
ここは、機会的にNone のときは is か is not とおぼえましょうw
最後に、繰り返す
older_post_linkがTrueでなければ、止まらず、次のプログラムが反応する。
older_post_link = response.urljoin(older_post_link)
# 次のページをのリクエストを実行する
yield scrapy.Request(older_post_link, callback=self.parse)
最後の、Requestとは?
HTTPリクエストを表します。これは通常スパイダーで生成され、ダウンローダーによって実行され、そして、 Response が生成されます。
responseとは?
HTTPレスポンスを表し、通常は(ダウンローダーによって)ダウンロードされ、処理のためにスパイダーに送られます。
selfとはなんだろう?
あとの疑問は、def parse(self, response): こちらに記載されている。
selfですね。
selfとはインスタンス自身を指す慣用語(※)です。
インスタンスメソッド内で、インタンス変数や別のインスタンスメソッドを参照する際、selfを用います。
引用:Pythonのselfの使い方を現役エンジニアが解説【初心者向け】
こちら最初の def の関数ぽいものを「メソッド」と呼びます。
単独で呼び出しできるのが「関数」
変数や値に付けて呼び出すのが「メソッド」
へーーー。メソッドは前(.)を付けて呼び出す関数とのことなので、
def parse(self, response):
クラス内のメソッドの第1引数には、selfを渡す。
だが、
def __init__(self, 引数リスト)
だがこいつよく見てみると。
クラスのインスタンス生成時に、インスタンス変数設定する あの
コンストラクタさんではない。初期化する必要がなければやらなくてよいのかな?
中途半端におわりますが、クラスについてはまだ勉強不足なので、学習して別の機会にまとめたいと思います!
class ScrapyBlogSpiderSpider(scrapy.Spider):
基礎だと思うが、class 新規クラス名(継承したいクラス名):
そもそも継承しているということか。
なので、ドキュメントにも、
scrapy.Spider をサブクラス化
と書かれているのかな。
https://doc-ja-scrapy.readthedocs.io/ja/latest/intro/tutorial.html#our-first-spider