3

私は Python Web クローラーを作成しており、それをマルチスレッドにしたいと考えています。これで基本的な部分が完成しました。以下はその機能です。

  1. スレッドはキューから URL を取得します。

  2. スレッドはページからリンクを抽出し、リンクがプール (セット) に存在するかどうかを確認し、新しいリンクをキューとプールに配置します。

  3. スレッドは URL と http 応答を csv ファイルに書き込みます。

しかし、クローラーを実行すると、最終的には常にスタックし、適切に終了しません。Python の公式ドキュメントを確認しましたが、まだ手がかりがありません。

以下はコードです:

#!/usr/bin/env python
#!coding=utf-8

import requests, re, urlparse
import threading
from Queue import Queue
from bs4 import BeautifulSoup

#custom modules and files
from setting import config


class Page:

    def __init__(self, url):

        self.url = url
        self.status = ""
        self.rawdata = ""
        self.error = False

        r = ""

        try:
            r = requests.get(self.url, headers={'User-Agent': 'random spider'})
        except requests.exceptions.RequestException as e:
            self.status = e
            self.error = True
        else:
            if not r.history:
                self.status = r.status_code
            else:
                self.status = r.history[0]

        self.rawdata = r

    def outlinks(self):

        self.outlinks = []

        #links, contains URL, anchor text, nofollow
        raw = self.rawdata.text.lower()
        soup = BeautifulSoup(raw)
        outlinks = soup.find_all('a', href=True)

        for link in outlinks:
            d = {"follow":"yes"}
            d['url'] = urlparse.urljoin(self.url, link.get('href'))
            d['anchortext'] = link.text
            if link.get('rel'):
                if "nofollow" in link.get('rel'):
                    d["follow"] = "no"
            if d not in self.outlinks:
                self.outlinks.append(d)


pool = Queue()
exist = set()
thread_num = 10
lock = threading.Lock()
output = open("final.csv", "a")

#the domain is the start point
domain = config["domain"]
pool.put(domain)
exist.add(domain)


def crawl():

    while True:

        p = Page(pool.get())

        #write data to output file
        lock.acquire()
        output.write(p.url+" "+str(p.status)+"\n")
        print "%s crawls %s" % (threading.currentThread().getName(), p.url)
        lock.release()

        if not p.error:
            p.outlinks()
            outlinks = p.outlinks
            if urlparse.urlparse(p.url)[1] == urlparse.urlparse(domain)[1] :
                for link in outlinks:
                    if link['url'] not in exist:
                        lock.acquire()
                        pool.put(link['url'])
                        exist.add(link['url'])
                        lock.release()
        pool.task_done()            


for i in range(thread_num):
    t = threading.Thread(target = crawl)
    t.start()

pool.join()
output.close()

どんな助けでも大歓迎です!

ありがとう

マーカス

4

1 に答える 1

3

クロール機能に、出口パスのない無限の while ループがあります。あなたが言うように、条件Trueは常に評価されTrue、ループが続きます。

正常に終了しない

クロール関数の while ループを変更して、条件を含めます。たとえば、csv ファイルに保存されたリンクの数が特定の最小数を超えた場合、while ループを終了します。

つまり、

def crawl():
    while len(exist) <= min_links:
        ...
于 2013-01-18T17:12:47.343 に答える