gpt4 book ai didi

python - 页面链接和该子页面的链接。递归/线程

转载 作者:行者123 更新时间:2023-12-03 12:59:02 24 4
gpt4 key购买 nike

我正在制作一个用于下载网站内容的函数,然后在该站点中查找链接,对于每个链接,我都递归调用相同的函数,直到第7级为止。问题是,这需要花费很多时间,因此我一直在寻找使用线程池来管理此调用的方法,但我不知道如何准确地将这些任务划分为线程池。

这是我的实际代码,没有线程池。

import requests
import re

url = 'https://masdemx.com/category/creatividad/?fbclid=IwAR0G2AQa7QUzI-fsgRn3VOl5oejXKlC_JlfvUGBJf9xjQ4gcBsyHinYiOt8'


def searchLinks(url,level):
print("level: "+str(level))
if(level==3):
return 0

response = requests.get(url)
enlaces = re.findall(r'<a href="(.*?)"',str(response.text))

for en in enlaces:
if (en[0] == "/" or en[0]=="#"):
en= url+en[1:]
print(en)
searchLinks(en,level+1)


searchLinks(url,1)

最佳答案

对于初学者,请注意,这可能是一个很大的操作。例如,如果每个页面平均只有10个唯一链接,则要递归7层深度,则您正在查看超过1000万个请求。
另外,我将使用像BeautifulSoup这样的HTML解析库而不是regex,这是一种抓取HTML的脆弱方法。避免打印到标准输出,这也会减慢工作速度。
至于线程,一种方法是使用工作队列。 Python的queue class是线程安全的,因此您可以创建一个工作线程池来轮询以从队列中检索URL。当线程获取URL时,它会找到页面上的所有链接,并将相关的URL(或页面数据,如果您愿意)附加到全局列表(在CPython上为thread-safe operation);对于其他实现,请在共享数据结构)。 URL已排队在工作队列中,并且过程继续进行。
当级别达到0时,线程退出,因为我们使用的是BFS而不是使用堆栈的DFS。这里(可能是安全的)假设是链接的级别比深度更多。
并行性来自于线程阻塞了等待请求响应的线程,从而使CPU可以运行另一个响应到达的线程来执行HTML解析和队列工作。
如果您想在多个内核上运行以帮助并行化工作负载的CPU约束部分,请添加read this blog post about the GIL并查看生成程序。但是仅线程就可以为您提供并行化的许多方法,因为瓶颈是受I/O约束的(等待HTTP请求)。
这是一些示例代码:

import queue
import requests
import threading
import time
from bs4 import BeautifulSoup

def search_links(q, urls, seen):
while 1:
try:
url, level = q.get()
except queue.Empty:
continue

if level <= 0:
break

try:
soup = BeautifulSoup(requests.get(url).text, "lxml")

for x in soup.find_all("a", href=True):
link = x["href"]

if link and link[0] in "#/":
link = url + link[1:]

if link not in seen:
seen.add(link)
urls.append(link)
q.put((link, level - 1))
except (requests.exceptions.InvalidSchema,
requests.exceptions.ConnectionError):
pass

if __name__ == "__main__":
levels = 2
workers = 10
start_url = "https://masdemx.com/category/creatividad/?fbclid=IwAR0G2AQa7QUzI-fsgRn3VOl5oejXKlC_JlfvUGBJf9xjQ4gcBsyHinYiOt8"
seen = set()
urls = []
threads = []
q = queue.Queue()
q.put((start_url, levels))
start = time.time()

for _ in range(workers):
t = threading.Thread(target=search_links, args=(q, urls, seen))
threads.append(t)
t.daemon = True
t.start()

for thread in threads:
thread.join()

print(f"Found {len(urls)} URLs using {workers} workers "
f"{levels} levels deep in {time.time() - start}s")
这是在我不是特别快的机器上运行的一些示例:
$ python thread_req.py
Found 762 URLs using 15 workers 2 levels deep in 33.625585317611694s
$ python thread_req.py
Found 762 URLs using 10 workers 2 levels deep in 42.211519956588745s
$ python thread_req.py
Found 762 URLs using 1 workers 2 levels deep in 105.16120409965515s
在这种小批量生产中,性能提高了3倍。在较大的运行量中,我遇到了最大的请求错误,因此这只是一个玩具示例。

关于python - 页面链接和该子页面的链接。递归/线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53402464/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com