- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我已经构建了一个爬虫,它必须在大约 500 万个页面上运行(通过增加 url ID)然后解析包含我需要的信息的页面。
使用在 url (200K) 上运行的算法并保存好结果和坏结果后,我发现我浪费了很多时间。我可以看到有一些返回的减数可以用来检查下一个有效的 url。
你可以很快看到减数(前几个“好 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 的好结果,我知道我在浪费时间并且需要优化它,所以我运行了一些统计数据并构建了一个函数来检查 url,同时将 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)
基本上做的是 -checkNextID(ID) 正在获取我知道的第一个 id,其中包含减 8 的数据,因此第一次迭代将匹配第一个“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。
你可以看到剩下的代码 here
运行代码后我得到了大约 950~ 好的结果,突然引发了一个异常 -
"somethin went wrong: maximum recursion depth exceeded while calling a Python object"
我可以在 WireShark 上看到 scipt 卡在 id - 510009541 上(我以 510000003 开始我的脚本),在我注意到错误并停止它之前,脚本尝试了几次使用该 ID 获取 URL。
看到我得到了相同的结果,但比我的旧脚本快 25 倍至 40 倍,HTTP 请求更少,非常精确,我真的很兴奋,我只错过了 1000 个好结果的 1 个结果,这是由我,5M 次朗姆酒是不可能的,我的旧脚本运行了 30 个小时,得到了 14-15K 的结果,而我的新脚本在 5-10 分钟内给了我 960~ 个结果。
我阅读了有关堆栈限制的信息,但我试图在 Python 中实现的算法必须有一个解决方案(我无法回到我的旧 “算法”,它永远不会结束)。
谢谢!
最佳答案
Python 对递归没有很好的支持,因为它缺少 TRE (Tail Recursion Elimination)。
这意味着对递归函数的每次调用都会创建一个函数调用堆栈,因为堆栈深度有一个限制(默认为 1000),您可以通过 sys.getrecursionlimit
查看(当然您可以使用 sys.setrecursionlimit 更改它,但不建议这样做)您的程序在达到此限制时最终会崩溃。
由于其他答案已经为您提供了一种更好的方法来解决您的情况(即通过简单循环替换递归),如果您仍想使用递归,则还有另一种解决方案,即使用其中一个许多像这样在 python 中实现 TRE 的秘诀 one .
注意:我的回答旨在让您更深入地了解为什么会出现错误,我不建议您使用我已经解释过的 TRE,因为在您的情况下,循环会更好,更易于阅读。
关于Python:调用 Python 对象时超出了最大递归深度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6809402/
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!