我有以下函数,检索给定的网页,并使用EasyList的缩短版本(17,000条规则)返回页面上的广告数量。使用多处理,它在2天多一点的时间内就刮掉了18,000页(当时还不错)。但是,我现在有一个10倍大的数据集,所以这个运行时并不特别理想。由于for循环中的这一行result = len(document.xpath(rule)),我怀疑它是以二次形式运行的。
我对XPath/lxml一点也不熟悉,所以最好能给出一些关于如何提高效率的建议,或者至少说明一下我是否能让它运行得更快。
import lxml.html
import requests
import cssselect
import pandas as pd
from multiprocessing import Pool
def count_ads(url):
rules_file = pd.read_csv("easylist_general_hide.csv", sep="\t",header=None)
try:
html = requests.get(url,timeout=5).text
except:
print(f"Page not found or timed out: {url}")
return
count = 0
translator = cssselect.HTMLTranslator()
for rule in rules_file[0]:
try:
rule = translator.css_to_xpath(rule[2:])
document = lxml.html.document_fromstring(html)
result = len(document.xpath(rule))
if result>0:
count = count+result
except:
pass
return count```发布于 2023-03-13 04:13:38
显然,您正在使用这个库:https://pypi.org/project/cssselect测量的处理刮过的页面的时间是10秒,我们希望减少这个时间。
OP中遗漏了许多重要的细节,包括对实际运行的轮廓仪观察。
我能看到至少有一件事可以立即得到改善。一个常数可以从循环中吊起。
html = requests.get(url,timeout=5).text
...
for rule in rules_file[0]:
...
rule = translator.css_to_xpath(rule[2:])
document = lxml.html.document_fromstring(html)
result = len(document.xpath(rule))看起来,常量的document解析可能会被提升,类似于translator已经被悬挂的方式。不需要重新计算它17K次,每条规则一次。
document = lxml.html.document_fromstring(html)
for rule in rules_file[0]:
...假定给定的工作进程将处理多个URL。因此,对于N个页面,我们调用.css_to_xpath() 1.7e4×N次。看起来这里可能有一个缓存的机会。一种天真的方法只需在缓存装潢师上就行了:
@lru_cache(max_size=17_400)
def get_xpath(...):但也可能有一些微妙的要求,比如所有的论点都是可以理解的。如果你遇到这样的麻烦,不要放弃。必须有一些方法来避免对相同的旧规则数据进行乏味的重复xpath提取。
一万七千条规则听起来挺多的。我敢打赌他们中的一些人经常触发,而有些人很少,也许是零次在你的语料库中。
你有时间和资源的限制。显然还不到20天。根据它们的有用程度排列顺序规则,并在您刚收到的页面上运行它们中的前一千条。公布初步结果。决定你是想回去尝试下一千条规则,还是一万条规则。
寻找模式。也许URL的主机名预测了最有可能应用于页面的100条规则。
这个计划有两个部分:
前者的内存占用非常小,与后者不同。这对调度服务器资源有影响。
考虑打破一个只关注于发布.get()s (带有超时)的“获取”阶段,然后将结果持久化到磁盘。
然后,随后的“计算”阶段可以分析获取的页面,可能会在10秒钟内完成。
短期基准。
然后用pypy再试一次。有时候会赢的。
https://codereview.stackexchange.com/questions/283923
复制相似问题