4

私は最近python-requestsモジュールを調べました。それを使って簡単な Web クローラーを書きたいと思います。開始 URL のコレクションを指定して、開始 URL の Web ページ コンテンツから他の URL を検索し、新しい URL を入力としてコールバックとして同じ関数を再度呼び出す Python 関数を作成したいと考えています。最初は、イベント フックがこの目的に適したツールであると考えていましたが、そのドキュメント部分は非常にまばらです。別のページで、イベントフックに使用される関数は、渡されたものと同じオブジェクトを返さなければならないことを読みました。したがって、イベント フックは明らかにこの種のタスクには適していません。それとも単純に気がつかなかった...

ここに私がやりたいことのいくつかの疑似コードがあります(疑似Scrapyスパイダーから借用):

import lxml.html    

def parse(response):
    for url in lxml.html.parse(response.url).xpath('//@href'):
        return Request(url=url, callback=parse)

誰かがpython-requestsでそれを行う方法について洞察を与えることができますか? イベントフックはそのための適切なツールですか、それとも別のものが必要ですか? (注:さまざまな理由により、Scrapy は私にとって選択肢ではありません。)どうもありがとうございました!

4

1 に答える 1

7

これが私がそれを行う方法です:

import grequests
from bs4 import BeautifulSoup


def get_urls_from_response(r):
    soup = BeautifulSoup(r.text)
    urls = [link.get('href') for link in soup.find_all('a')]
    return urls


def print_url(args):
    print args['url']


def recursive_urls(urls):
    """
    Given a list of starting urls, recursively finds all descendant urls
    recursively
    """
    if len(urls) == 0:
        return
    rs = [grequests.get(url, hooks=dict(args=print_url)) for url in urls]
    responses = grequests.map(rs)
    url_lists = [get_urls_from_response(response) for response in responses]
    urls = sum(url_lists, [])  # flatten list of lists into a list
    recursive_urls(urls)

私はコードをテストしていませんが、一般的なアイデアはそこにあります。

パフォーマンス向上grequestsの代わりに使用していることに注意してください。は基本的に であり、私の経験では、 と非同期でリンクを取得するため、この種のタスクでははるかに高速です。requestsgrequestgevent+requestgevent


編集:再帰を使用しない同じアルゴリズムは次のとおりです。

import grequests
from bs4 import BeautifulSoup


def get_urls_from_response(r):
    soup = BeautifulSoup(r.text)
    urls = [link.get('href') for link in soup.find_all('a')]
    return urls


def print_url(args):
    print args['url']


def recursive_urls(urls):
    """
    Given a list of starting urls, recursively finds all descendant urls
    recursively
    """
    while True:
        if len(urls) == 0:
            break
        rs = [grequests.get(url, hooks=dict(args=print_url)) for url in urls]
        responses = grequests.map(rs)
        url_lists = [get_urls_from_response(response) for response in responses]
        urls = sum(url_lists, [])  # flatten list of lists into a list

if __name__ == "__main__":
    recursive_urls(["INITIAL_URLS"])
于 2012-09-02T17:59:19.023 に答える