我正在使用selenium
和Python来做一个大项目。我必须一个接一个地浏览320000个网页(320K(,抓取细节,然后睡一秒钟,继续前进。
如下所示:
links = ["https://www.thissite.com/page=1","https://www.thissite.com/page=2", "https://www.thissite.com/page=3"]
for link in links:
browser.get(link )
scrapedinfo = browser.find_elements_by_xpath("*//div/productprice").text
open("file.csv","a+").write(scrapedinfo)
time.sleep(1)
最大的问题是:太慢了
使用此脚本I将需要数天或可能需要数周。
- 有办法提高速度吗?例如,通过访问多个同时链接并同时抓取
我花了几个小时在谷歌和Stackoverflow上寻找答案,只找到了关于multiprocessing
的答案。
但是,我无法将其应用到我的脚本中。
线程方法
- 您应该从
threading.Thread
开始,它将显著提升性能(此处解释(。线程也比进程轻。您可以使用futures.ThreadPoolExecutor
,每个线程都使用自己的网络驱动程序。还可以考虑为您的网络驱动程序添加headless
选项。使用chrome网络驱动程序的示例如下:
from concurrent import futures
def selenium_work(url):
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless")
driver = webdriver.Chrome(options=chromeOptions)
#<actual work that needs to be done be selenium>
# default number of threads is optimized for cpu cores
# but you can set with `max_workers` like `futures.ThreadPoolExecutor(max_workers=...)`
with futures.ThreadPoolExecutor() as executor:
# store the url for each thread as a dict, so we can know which thread fails
future_results = { url : executor.submit(selenium_work, links) for url in links }
for url, future in future_results.items():
try:
future.result() # can use `timeout` to wait max seconds for each thread
except Exception as exc: # can give a exception in some thread
print('url {:0} generated an exception: {:1}'.format(url, exc))
还考虑存储使用
threading.local()
在每个线程上初始化的chrome-driver
实例。从这里开始,他们报告了合理的性能改进。考虑一下在硒的页面上直接使用
BeautifulSoup
是否可以提供其他一些加速。这是一个非常快速和稳定的一揽子计划。例如driver.get(url) ... soup = BeautifulSoup(driver.page_source,"lxml") ... result = soup.find('a')
其他方法
虽然我个人认为使用
concurrent.futures.ProcessPoolExecutor()
没有太大好处,但你可以尝试一下。事实上,它比我在Windows上进行的实验中的线程要慢。此外,在Windows上,您对pythonProcess
有许多限制。考虑一下您的用例是否可以通过使用基于asyncio的异步web驱动程序客户端来满足这听起来确实很有希望,尽管有很多局限性。
考虑RequestsHtml是否解决了javascript加载问题。由于它声称完全支持JavaScript在这种情况下,您可以将它与
BeautifulSoup
一起用于标准的数据抓取方法。
您可以使用paralel执行。为十个将使用相同代码的TC设计站点列表,只是方法名称不同(方法1、方法2、方法3…(。你会提高速度。浏览器的数量取决于你们的硬盘性能。在上查看更多信息https://www.guru99.com/sessions-parallel-run-and-dependency-in-selenium.html
主要是使用TestNG和编辑.xml文件,并设置要使用的线程数量。像这样:
<suite name="TestSuite" thread-count="10" parallel="methods" >
如果你不想针对机器人抓取过于安全的网站,最好使用请求,它将把你的时间从几天减少到几个小时,并实现多线程和多处理。步骤太长,无法完成,这里只是一些想法:
def threader_run(data):
futures = []
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
for i in data:
futures.append(executor.submit(scrapper,i))
for future in concurrent.futures.as_completed(futures):
print(future.result())
data = {}
data['process1'] = []
data['process2'] = []
data['process3'] = []
if __name__ == "__main__":
for x in data:
jobs = []
p = Process(target=threader_run,args(data[x],))
jobs.append(p)
p.start()
print(f'Started - {x}')
基本上,这是首先编译所有链接,然后将它们拆分为3个阵列,以便同时运行3个进程(您可以运行更多进程,这取决于您的cpu核心以及这些作业的数据密集程度(。之后,根据您的项目规模,进一步拆分这些阵列可能会超过10个,甚至100个。这将运行最多有8个工作线程的线程池,然后它将运行您的最终函数。
这里有3个流程和8个工人,您看到的是24倍的速度提升但是,使用请求库是必要的如果您为此使用硒,普通计算机/笔记本电脑将冻结。因为这意味着24个浏览器同时运行