2

免責事項この質問に直接答えるのは難しく、答えるにはスクレイピーとプログラムの順序付けについてよく理解している必要があります。質問を直接答えやすいものに縮小するのは難しいです。

私の知る限り、アイテム パイプライン ハンドラからリクエストを返すことはできません。フォーラムから特定のカテゴリのすべての投稿を解析しようとしています。フォーラムを横断する私の戦略は次のとおりです。

  1. カテゴリ内のすべてのページのリストを作成し、それらをダウンローダーに送信して取得します。
  2. 各ページ内のすべてのトピックを取得し、アイテム パイプラインに送信します。
  3. すべてのページ アイテムが処理される (リレーショナル データベースに挿入される) のを待ってから、すべてのトピックのトラバースを開始します。

ステップ 3 をシーケンスする方法がわかりません。シーケンス ロジックを支援するために、次の 2 つのオブジェクト (最後にリストされています) を使用しています。category::process_pageトピック ページをトラバースする際に使用されるリクエスト ハンドラです。

カテゴリ クラス :

フェーズ 1 の終了は、すべてのトピック ページが受信されたことを表します。フェーズ 2 の終了は、アイテム パイプラインがすべてのトピックの基礎作業を処理したことを意味します。

特定のトピック リスト ページ内のすべてのトピックを表すトピック クラス。フェーズ 1 の終了は、ページ内のすべてのトピックがデータベースに送信されたことを意味します。ページ内の各トピックがデータベースに追加されると、そのページはカテゴリから削除されます。すべてのページが完了すると、クローラーはすべてのトピックのダウンロードに移ります。

では、アイテム パイプラインで実行されるロジックを介して、カテゴリ フェーズ 2 が終了するのを待つことができるように、ダウンローダをブロックするにはどうすればよいでしょうか? これのためにスクレイピーにいくつかの機械がありますか? おそらく、アイテム パイプライン内からダウンローダ ロジックを再起動できますか?

おそらくこれを行う方法はたくさんありますが、私はPythonとC ++ / Cシステムプログラマーが初めてです。

注:私の最初の設計は、3 ~ 4 個の異なるスパイダーで行う予定でした。1 つはフォーラム階層を取得し、2 番目はすべてのトピックをダウンロードし、3 番目はすべての投稿を取得し、4 番目は更新が必要なトピックをマークします。しかし、この問題にはもっと自然な解決策があるはずです。最後の 3 つのスパイダーを 1 つにまとめたいと思います。

スプーンは、bash に頼らずにスパイダーを起動するロジックを提供するという答えを受け入れます (GUI からスパイダーを駆動できると便利です)。それから、ドライバー プログラムを作成して、最初の設計に固執することができます。

###############################################################################
class TopicPageItemBundle:
  def __init__(self,topic_page_url,category_item_bundle):
    self.url = topic_page_url
    self.topics = set()
    self.topics_phase1 = set()
    self.category_item_bundle = category_item_bundle

  def add_topic(self, topic_url):
    self.topics.add(topic_url)
    self.topics_phase1.add(topic_url)

  def topic_phase1_done(self, topic_url):
    self.topics.remove(topic_url)
    if len(self.topics_phase1) == 0:
      return true
    else:
      return false
###############################################################################
class CategoryItemBundle:
  def __init__(self,forum_id):
    self.topic_pages = {}
    self.topic_pages_phase1 = set()
    self.forum_id = forum_id

  def add_topic_page(self,topic_page_url):
    tpib = TopicPageItemBundle(topic_page_url,self)
    self.topic_pages[topic_page_url] = tpib 
    self.topic_pages_phase1.add(topic_page_url)
    self.topic_pages_phase2.add(topic_page_url)

  def process_page(self, response):
    return_items = []
    tp = TopicPage(response,self)
    pagenav = tp.nav()
    log.msg("received " + pagenav.make_nav_info(), log.INFO)

    page_bundle = self.topic_pages[response.url]

    posts = tp.extract_posts(self.forum_id)
    for post in posts:
      if post != None:
        page_bundle.add_topic(post["url"])
        post["page_topic_bundle"] = page_bundle
    return return_items

  # phase 1 represents finishing the retrieval of all topic pages in a forum
  def topic_page_phase1_done(self, topic_page_url):
    self.topic_pages_phase1.remove(topic_page_url)
    if len(self.topic_pages_phase1) == 0:
      return true
    else:
      return false

  def topic_page_phase2_done(self,topic_page_url)
    self.topic_pages_phase2.remove(topic_page_url)
    if len(self.topic_pages_phase2) == 0:
      return true
    else:
      return true
###############################################################################
4

2 に答える 2

2

すべてのトピックのリストを取得してデータベースに保存した後にのみ、各トピックのスクレイピングを開始する理由はありますか?

私のスクレイピーフローは通常これだからです:トピックのリストを含むページを取得します。各トピックのリンクを見つけ、トピックをスクレイピングするためのコールバックでそれぞれのリクエストを生成します。リストの次のページへのリンクを見つけて、同じコールバックのコールバックを生成します。等々。

私の知る限り、コールバックから最初にトピック アイテムを生成し、次にリクエストを生成すると、パイプラインは生成されたアイテムですぐに実行されます。

于 2012-06-25T04:01:30.637 に答える
0

この問題を解決する 1 つの方法は、アイテム パイプライン内のトピック処理用のコードをリクエスト ハンドラーにマージすることです。本質的に、アイテム パイプラインとダウンローダの間の分割を取り除くことで、同期なしで、データベースにすべてのトピックが挿入されたことを示すフェーズが 1 つだけになります。

ただし、スクレイピーで「物事が行われることを意図した方法」をバイパスするため、これは少し不自然に思えます。同期を必要としないため、投稿のトピックのスクレイピングを開始するときは、引き続きアイテム パイプラインを使用できます。

于 2012-06-23T17:44:01.723 に答える