7

私は Scrapy、特に Scrapy のCrawlSpiderクラスを使用して、特定のキーワードを含む Web リンクをスクレイピングしています。Django プロジェクトに接続されている SQLite データベースからエントリを取得するかなり長いstart_urlsリストがあります。スクレイピングした Web リンクをこのデータベースに保存したいと考えています。

私は 2 つの Django モデルを持っています.1 つは などの開始 URL 用で、もう 1 つは などのスクレイピングされhttp://example.comた Web リンク用です。http://example.com/website1http://example.com/website2start_urls

Web リンク モデルは、開始 URL モデルに対して多対 1 の関係を持っています。つまり、Web リンク モデルは、開始 URL モデルへの Foreignkey を持っています。スクレイピングされた Web リンクをデータベースに適切に保存するには、スクレイピングされた Web リンクが属する開始 URL をCrawlSpiderのメソッドに伝える必要があります。parse_item()どうやってやるの?使用する開始 URL を明示的に定義する必要があるため、 Scrapy のDjangoItemクラスはこの点では役に立ちません。

つまり、現在使用されている開始 URL をメソッドに渡すにはどうすればよいparse_item()でしょうか。それにより、適切なスクレイピングされた Web リンクと一緒にデータベースに保存できます。何か案は?前もって感謝します!

4

4 に答える 4

9

デフォルトでは、元の開始URLにアクセスできません。

ただし、メソッドをオーバーライドmake_requests_from_urlして、開始URLをに入れることができますmeta。次に、解析でそこから抽出できます(その解析メソッドで後続のリクエストを生成する場合は、その開始URLを転送することを忘れないでください)。


私はこれまで作業したことがなく、マキシムが提案するものがあなたのために機能するかもしれませんが、可能なリダイレクトの後にURLがあるCrawlSpiderことを覚えておいてください。response.url

これは私がそれを行う方法の例ですが、これは単なる例であり(scrapyチュートリアルから取得)、テストされていません:

class MySpider(CrawlSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com']

    rules = (
        # Extract links matching 'category.php' (but not matching 'subsection.php')
        # and follow links from them (since no callback means follow=True by default).
        Rule(SgmlLinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

        # Extract links matching 'item.php' and parse them with the spider's method parse_item
        Rule(SgmlLinkExtractor(allow=('item\.php', )), callback='parse_item'),
    )

    def parse(self, response): # When writing crawl spider rules, avoid using parse as callback, since the CrawlSpider uses the parse method itself to implement its logic. So if you override the parse method, the crawl spider will no longer work.
        for request_or_item in CrawlSpider.parse(self, response):
            if isinstance(request_or_item, Request):
                request_or_item = request_or_item.replace(meta = {'start_url': response.meta['start_url']})
            yield request_or_item

    def make_requests_from_url(self, url):
        """A method that receives a URL and returns a Request object (or a list of Request objects) to scrape. 
        This method is used to construct the initial requests in the start_requests() method, 
        and is typically used to convert urls to requests.
        """
        return Request(url, dont_filter=True, meta = {'start_url': url})

    def parse_item(self, response):
        self.log('Hi, this is an item page! %s' % response.url)

        hxs = HtmlXPathSelector(response)
        item = Item()
        item['id'] = hxs.select('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
        item['name'] = hxs.select('//td[@id="item_name"]/text()').extract()
        item['description'] = hxs.select('//td[@id="item_description"]/text()').extract()
        item['start_url'] = response.meta['start_url']
        return item

ご不明な点がございましたら、お問い合わせください。ところで、PyDevの「定義に移動」機能を使用すると、スクレイプなソースを確認し、どのパラメーターRequestmake_requests_from_urlおよび他のクラスとメソッドが期待するかを理解できます。最初は難しいように思われるかもしれませんが、コードに入ると時間を節約できます。

于 2012-05-15T17:35:13.323 に答える
3

私が問題を正しく理解していれば、 から URL を取得してからresponse.urlに書き込むことができますitem['url']

スパイダーで:item['url'] = response.url

パイプライン内: url = item['url'].

または、warvariuc が書いたようにresponse.url入れます。meta

于 2012-05-16T04:00:32.123 に答える
1

Stephan Seyboth のアドバイスに従い、Scrapy 2.5.0 では、_parse_responseクラスのオーバーライドに成功しましたCrawlSpider。変更が必要な現在のメソッド定義については、Scrapy の crawl.pyを確認してください。また、変数を meta に追加しましたmake_requests_from_url

def _parse_response(self, response, callback, cb_kwargs, follow=True):
    if callback:
        cb_res = callback(response, **cb_kwargs) or ()
        cb_res = self.process_results(response, cb_res)
        for request_or_item in iterate_spider_output(cb_res):
            yield request_or_item
    if follow and self._follow_links:
        for request_or_item in self._requests_to_follow(response):
            request_or_item.meta['start_url'] = response.meta['start_url']
            yield request_or_item

def make_requests_from_url(self, url):
    return Request(url, dont_filter=True, meta = {'start_url': url})

次にresponse.meta['start_url']parse_itemメソッドでアクセスできます。これには、元の start_url が含まれます。

于 2021-06-07T01:26:55.067 に答える