python - 使用 selenium 一次抓取多个网页
问题描述
我正在使用selenium
Python 做一个大项目。我必须一个一个地浏览 320.000 个网页(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)
最大的问题:太慢了!
使用这个脚本,我需要几天甚至几周的时间。
- 有没有办法提高速度?例如,通过同时访问多个链接并一次全部抓取?
我花了几个小时在 google 和 Stackoverflow 上寻找答案,但只找到了multiprocessing
.
但是,我无法在我的脚本中应用它。
解决方案
线程方法
- 您应该从它开始,
threading.Thread
它会给您带来相当大的性能提升(在此处解释)。线程也比进程轻。您可以使用futures.ThreadPoolExecutor
每个线程使用它自己的 webdriver。还可以考虑为您的 webdriver 添加headless
选项。下面使用 chrome-webdriver 的示例:
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))
还考虑使用 . 存储
chrome-driver
在每个线程上初始化的实例threading.local()
。从这里他们报告了合理的性能改进。考虑
BeautifulSoup
直接在 selenium 的页面上使用是否可以提供其他一些加速。这是一个非常快速且稳定的软件包。示例类似driver.get(url) ... soup = BeautifulSoup(driver.page_source,"lxml") ... result = soup.find('a')
其他方法
虽然我个人没有看到使用
concurrent.futures.ProcessPoolExecutor()
你的太多好处,但可以尝试一下。事实上,它比我在 Windows 上的实验中的线程慢。同样在 Windows 上,您对 python 有很多限制Process
。考虑是否可以通过使用构建在 asyncio 上的异步 webdriver 客户端来满足您的用例。这听起来确实很有希望,尽管有很多限制。
考虑Requests-Html是否可以解决您的 javascript 加载问题。因为它声称完全支持 JavaScript!在这种情况下,您可以将它与
BeautifulSoup
标准数据抓取方法一起使用。
推荐阅读
- android - 我的问题是要了解firebase数据库的数据结构
- sql - 如何从 redshift 的列中删除 HTML 标签?
- microservices - OpenAPI / JDL 和 Avro 模式:生成实体/对象定义的最佳实践是什么?
- node.js - Microsoft Graph API calendarView 增量端点未响应初始请求
- qt - MyButton 不是类型:-1 文件名大小写不匹配
- jquery - Tablesorter 的 filter_selectSource 使用服务器端分页删除当前页面不可用的选项并选择选项准备
- c++ - Visual Studio 2017 IntelliSense 不适用于 C++
- eigen3 - Eigen::Map 构造函数抱怨“不是常量表达式”
- webpack - 应用程序未使用 webpack AOT 为 prd 构建 nativescript
- postgresql - 如何在 postgresql 中使用 postgres_fdw 从另一个数据库中获取记录