読者です 読者をやめる 読者になる 読者になる

無駄と文化

実用的ブログ

Scrapy で相対パスを解決して絶対パスに変換 for v1.0.4

Scrapy Python

スクレイピングネタです。

Scrapy は Spider の perse() メソッドの中で新しい Request オブジェクトを yield してあげるだけで、次々に URL を辿ってクローリングしていけるので便利ですね。
例えば、response.xpath("//a/@href").extract() とかすればページの中のリンクを取得するのも容易です。

ただし、取得したリンクの href が全て絶対パスで書かれている保証はありません。
もしも、相対パスで書かれていた場合は(そういう場合は多いでしょう)、相対パスを解決して絶対パスにしてあげなくてはいけません。


Python で相対パスの解決をしようと思えば、urlparse モジュールの urljoin() を使うのが普通です。
が、Scrapy には urlparse.urljoin() 相当のメソッドが最初から組み込まれているので、そちらを利用するのが便利です。


サイトの全ページを辿って <title> を取得する Spider を例に見ると、

# -*- coding: utf-8 -*-
import scrapy


class SampleSpider(scrapy.Spider):
    name = "sample"
    allowed_domains = ["example.com"]

    start_urls = [
        "http://example.com/",
    ]

    def parse(self, response):
        # <title> タグの中を取得して返す
        title = response.xpath("//title/text()").extract_first()
        yield {
            "url": response.url,
            "title": title,
        }

        for href in response.xpath('//a/@href').extract():
            # href を urljoin() で絶対パスに変換
            next_url = response.urljoin(href)

            # 新しい Request オブジェクトを返すことで、その URL が続いてクロールされる
            yield  scrapy.Request(next_url)

for文の中で response.urljoin(href) としています。
response.urljoin() は現在の URL をベースに相対パスを解決するので、これで urlparse.urljoin(response.url, href) と書いたときと同じ処理になります。

シンプルで、分かりやすいですね。


私からは以上です。