YSY*_*YSY 34 python algorithm recursion web-crawler depth
我已经构建了一个必须在大约5M页面上运行的爬虫(通过增加URL ID),然后解析包含"我需要"信息的页面.
在使用在网址(200K)上运行的算法并保存了好的和坏的结果后,我发现我浪费了很多时间.我可以看到有一些返回的减数我可以用来检查下一个有效的URL.
你可以很快地看到减数(少数第一个"好身份证") -
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
Run Code Online (Sandbox Code Playgroud)
在抓取大约200K网址之后,这给了我14K的好结果我知道我浪费时间并且需要优化它,所以我运行一些统计数据并构建了一个函数来检查网址,同时增加id为8\18\17\8(顶部返回减数)等'.
这是功能 -
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)
Run Code Online (Sandbox Code Playgroud)
什么基本上是-checkNextID(ID)获取我知道的第一个包含数据减去8的id,因此第一次迭代将匹配第一个"if isValid"子句(isValid(ID + 8)将返回True).
lastResult是一个保存最后一个已知url id的变量,因此我们将运行直到numOfRuns为止
isValid()是一个获取ID +其中一个副转义的函数,如果url包含我需要的内容,则返回True,并将url的汤对象保存到名为' curRes ' 的全局变量中,如果url没有,则返回False不包含我需要的数据.
parseHTML是一个获取汤对象(curRes)的函数,解析我需要的数据,然后将数据保存到csv,然后返回True.
如果isValid()返回True,我们将调用parseHTML(),然后尝试检查下一个ID +副减数(通过调用checkNextID(ID + subtrahends),如果它们都不会返回我正在寻找的东西我会用1增加它并再次检查,直到我找到下一个有效的URL.
你可以在这里看到其余的代码
在运行代码后,我得到了大约950个好结果,突然出现异常 -
"事情出错了:调用Python对象时超出了最大递归深度"
我可以在WireShark上看到scipt卡在id上 - 510009541(我用510000003启动了我的脚本),脚本尝试使用该ID获取几次url,然后我发现错误并停止了它.
我真的很兴奋地看到我得到了相同的结果,但比我的旧脚本快25倍-40倍,HTTP请求更少,非常精确,我只错过了1个结果1000个好结果,这是我发现的,它是不可能朗读5M次,我的旧脚本运行30个小时,当我的新脚本在5-10分钟内给我960~结果时得到14-15K结果.
我读到了堆栈限制,但是我必须有一个解决方案,我试图在Python中实现这个算法(我不能回到我原来的"算法",它永远不会结束).
谢谢!
mou*_*uad 36
Python没有很好的支持递归,因为它缺少TRE(尾递归消除).
这意味着每次调用递归函数都会创建一个函数调用堆栈,因为堆栈深度的限制(默认为1000)可以检出sys.getrecursionlimit
(当然你可以使用sys.setrecursionlimit更改它,但它不是建议)当程序达到此限制时,程序最终会崩溃.
由于其他答案已经为您提供了一个更好的方法来解决这个问题(通过简单的循环替换递归),如果您仍然想要使用递归,那么可以使用其中一种方法在这样的蟒蛇实施TRE 一个.
注意:我的回答是为了让您更深入地了解为什么会出现错误,我并不建议您使用TRE,因为在您的情况下,循环将更好,更容易阅读.
小智 23
您可以通过以下方式增加堆栈的容量:
import sys
sys.setrecursionlimit(10000)
Run Code Online (Sandbox Code Playgroud)
Dan*_* D. 14
这会将递归转换为循环:
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)
Run Code Online (Sandbox Code Playgroud)
您可以增加递归深度和线程堆栈大小。
import sys, threading
sys.setrecursionlimit(10**7) # max depth of recursion
threading.stack_size(2**27) # new thread will get stack of such size
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
93250 次 |
最近记录: |