1. ホーム
  2. python

[解決済み] Python: Pythonオブジェクトの呼び出し中に再帰の最大深度を超えた

2022-03-01 11:53:04

質問

私は約5Mページ(URL IDを増加させることによって)実行する必要があり、その後、私が必要とする情報を含むページをパースするクローラを構築しています。

200KのURLで実行するアルゴリズムを使用し、良い結果と悪い結果を保存した後、私は多くの時間を無駄にしていることに気づきました。私は、次の有効なURLを確認するために使用することができますいくつかの戻りsubstrahendsがあることを確認することができました。

は、非常に高速にサブトラヘンドを見ることができます(少数の最初の "良い ID" の少し例) - 。

510000011 # +8
510000029 # +18
510000037 # +8
510000045 # +8
510000052 # +7
510000060 # +8
510000078 # +18
510000086 # +8
510000094 # +8
510000102 # +8
510000110 # etc'
510000128
510000136
510000144
510000151
510000169
510000177
510000185
510000193
510000201

200KのURLをクロールして14Kの結果しか得られなかったので、時間を無駄にしていると思い、最適化する必要があると思いました。

これがその関数です。

def checkNextID(ID):
    global numOfRuns, curRes, lastResult
    while ID < lastResult:
        try:
            numOfRuns += 1
            if numOfRuns % 10 == 0:
                time.sleep(3) # sleep every 10 iterations
            if isValid(ID + 8):
                parseHTML(curRes)
                checkNextID(ID + 8)
                return 0
            if isValid(ID + 18):
                parseHTML(curRes)
                checkNextID(ID + 18)
                return 0
            if isValid(ID + 7):
                parseHTML(curRes)
                checkNextID(ID + 7)
                return 0
            if isValid(ID + 17):
                parseHTML(curRes)
                checkNextID(ID + 17)
                return 0
            if isValid(ID+6):
                parseHTML(curRes)
                checkNextID(ID + 6)
                return 0
            if isValid(ID + 16):
                parseHTML(curRes)
                checkNextID(ID + 16)
                return 0
            else:
                checkNextID(ID + 1)
                return 0
        except Exception, e:
            print "somethin went wrong: " + str(e)

は基本的に何をするかというと、-checkNextID(ID)は、データから8を引いたものを含む私が知っている最初のidを取得するため、最初の反復は最初の "if isValid" 節に一致します(isValid(ID + 8)は真を返す)。

最終結果 は最後に判明したURL IDを保存する変数で、numOfRunsが0になるまで実行します。

isValid() は、ID + 末尾の 1 つを取得し、url が必要なものを含んでいれば True を返し、url のスープオブジェクトをグローバル変数に保存する関数です。 curRes '、urlが必要なデータを含んでいない場合はFalseを返します。

パースHTML は、スープオブジェクト (curRes) を取得し、必要なデータをパースして、そのデータを csv に保存して、True を返す関数です。

isValid()がTrueを返したら、parseHTML()を呼び出し、次のID+subrahendsをチェックします(checkNextID(ID+subrahends)を呼び出して、どれも私が探しているものを返さない場合は1を増やして、次の有効なurlが見つかるまで再度チェックします)。

残りのコードを見ることができます ここで

を実行した後、950~の良好な結果が得られたのですが、突然例外が発生しました。

を呼び出している間に再帰的深度の最大値を超えてしまいました。 Pythonオブジェクト"。

WireSharkで、scriptがid - 510009541(私は510000003でスクリプトを開始しました)で止まっているのを確認しました。私がエラーに気づいて停止するまで、スクリプトは数回そのIDでURLを取得しようとしました。

同じ結果を得たのに、古いスクリプトより25倍から40倍も速く、HTTPリクエストも少なく、非常に正確で、1000の良い結果に対してたった1つの結果しか見逃していない、これは私にとっては発見です。

スタック制限について読みましたが、私がPythonで実装しようとしているアルゴリズムには解決策があるはずです(私は以前の アルゴリズム" このままでは終われません)。

ありがとうございました。

解決方法は?

これは、再帰をループに変える。

def checkNextID(ID):
    global numOfRuns, curRes, lastResult
    while ID < lastResult:
        try:
            numOfRuns += 1
            if numOfRuns % 10 == 0:
                time.sleep(3) # sleep every 10 iterations
            if isValid(ID + 8):
                parseHTML(curRes)
                ID = ID + 8
            elif isValid(ID + 18):
                parseHTML(curRes)
                ID = ID + 18
            elif isValid(ID + 7):
                parseHTML(curRes)
                ID = ID + 7
            elif isValid(ID + 17):
                parseHTML(curRes)
                ID = ID + 17
            elif isValid(ID+6):
                parseHTML(curRes)
                ID = ID + 6
            elif isValid(ID + 16):
                parseHTML(curRes)
                ID = ID + 16
            else:
                ID = ID + 1
        except Exception, e:
            print "somethin went wrong: " + str(e)