【发布时间】:2013-12-23 02:10:59
【问题描述】:
我正在使用 Selenium 和 Python 绑定来使用无头 Firefox 从网页中抓取 AJAX 内容。在我的本地机器上运行时它可以完美运行。当我在我的 VPS 上运行完全相同的脚本时,错误会出现在看似随机(但一致)的行上。我的本地和远程系统具有完全相同的操作系统/架构,所以我猜测差异与 VPS 相关。
对于这些回溯中的每一个,该行在抛出错误之前运行 4 次。
在执行 JavaScript 以将元素滚动到视图中时,我最常遇到此 URLError。
File "google_scrape.py", line 18, in _get_data
driver.execute_script("arguments[0].scrollIntoView(true);", e)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 396, in execute_script
{'script': script, 'args':converted_args})['value']
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 162, in execute
response = self.command_executor.execute(driver_command, params)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 355, in execute
return self._request(url, method=command_info[0], data=data)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 402, in _request
response = opener.open(request)
File "/usr/lib64/python2.7/urllib2.py", line 404, in open
response = self._open(req, data)
File "/usr/lib64/python2.7/urllib2.py", line 422, in _open
'_open', req)
File "/usr/lib64/python2.7/urllib2.py", line 382, in _call_chain
result = func(*args)
File "/usr/lib64/python2.7/urllib2.py", line 1214, in http_open
return self.do_open(httplib.HTTPConnection, req)
File "/usr/lib64/python2.7/urllib2.py", line 1184, in do_open
raise URLError(err)
urllib2.URLError: <urlopen error [Errno 111] Connection refused>
从元素中读取文本时,有时我会收到此 BadStatusLine。
File "google_scrape.py", line 19, in _get_data
if e.text.strip():
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 55, in text
return self._execute(Command.GET_ELEMENT_TEXT)['value']
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 233, in _execute
return self._parent.execute(command, params)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 162, in execute
response = self.command_executor.execute(driver_command, params)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 355, in execute
return self._request(url, method=command_info[0], data=data)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 402, in _request
response = opener.open(request)
File "/usr/lib64/python2.7/urllib2.py", line 404, in open
response = self._open(req, data)
File "/usr/lib64/python2.7/urllib2.py", line 422, in _open
'_open', req)
File "/usr/lib64/python2.7/urllib2.py", line 382, in _call_chain
result = func(*args)
File "/usr/lib64/python2.7/urllib2.py", line 1214, in http_open
return self.do_open(httplib.HTTPConnection, req)
File "/usr/lib64/python2.7/urllib2.py", line 1187, in do_open
r = h.getresponse(buffering=True)
File "/usr/lib64/python2.7/httplib.py", line 1045, in getresponse
response.begin()
File "/usr/lib64/python2.7/httplib.py", line 409, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python2.7/httplib.py", line 373, in _read_status
raise BadStatusLine(line)
httplib.BadStatusLine: ''
我遇到了几次套接字错误:
File "google_scrape.py", line 19, in _get_data
if e.text.strip():
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 55, in text
return self._execute(Command.GET_ELEMENT_TEXT)['value']
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py", line 233, in _execute
return self._parent.execute(command, params)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 162, in execute
response = self.command_executor.execute(driver_command, params)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 355, in execute
return self._request(url, method=command_info[0], data=data)
File "/home/ryne/.virtualenvs/DEV/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 402, in _request
response = opener.open(request)
File "/usr/lib64/python2.7/urllib2.py", line 404, in open
response = self._open(req, data)
File "/usr/lib64/python2.7/urllib2.py", line 422, in _open
'_open', req)
File "/usr/lib64/python2.7/urllib2.py", line 382, in _call_chain
result = func(*args)
File "/usr/lib64/python2.7/urllib2.py", line 1214, in http_open
return self.do_open(httplib.HTTPConnection, req)
File "/usr/lib64/python2.7/urllib2.py", line 1187, in do_open
r = h.getresponse(buffering=True)
File "/usr/lib64/python2.7/httplib.py", line 1045, in getresponse
response.begin()
File "/usr/lib64/python2.7/httplib.py", line 409, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python2.7/httplib.py", line 365, in _read_status
line = self.fp.readline(_MAXLINE + 1)
File "/usr/lib64/python2.7/socket.py", line 476, in readline
data = self._sock.recv(self._rbufsize)
socket.error: [Errno 104] Connection reset by peer
我在没有代理的情况下从 Google 抓取,所以我的第一个想法是我的 IP 地址被识别为 VPS 并受到 5 次页面操作限制或其他限制。但我最初的研究表明,这些错误不会因被阻止而产生。
如果您能深入了解这些错误的总体含义,或者在从 VPS 发出 HTTP 请求时的必要注意事项,我们将不胜感激。
更新
经过一番思考并研究了 webdriver 的真正含义——自动浏览器输入——我应该对为什么 remote_connection.py 会发出 urllib2 请求感到困惑。 WebElement 类的 text 方法似乎是 python 绑定的“额外”功能,它不是 Selenium 核心的一部分。这并不能解释上述错误,但它可能表明不应使用 text 方法进行抓取。
更新 2
我意识到,就我的目的而言,Selenium 的唯一功能是加载 ajax 内容。所以页面加载后,我用lxml解析源代码,而不是用Selenium获取元素,即:
html = lxml.html.fromstring(driver.page_source)
但是,page_source 是另一种导致调用urllib2 的方法,并且我在第二次使用它时始终收到BadStatusLine 错误。最小化urllib2 请求绝对是朝着正确方向迈出的一步。
更新 3
通过使用 javascript 获取源来消除 urllib2 请求更好:
html = lxml.html.fromstring(driver.execute_script("return window.document.documentElement.outerHTML"))
结论
可以通过在每几个请求之间执行time.sleep(10) 来避免这些错误。我想出的最好解释是 Google 的防火墙将我的 IP 识别为 VPS,因此将其置于一组更严格的阻止规则之下。
这是我最初的想法,但我仍然很难相信,因为我的网络搜索没有返回任何迹象表明上述错误可能是由防火墙引起的。
如果是这种情况,我认为可以使用代理绕过更严格的规则,尽管该代理可能必须是本地系统或 tor 以避免相同的限制。
【问题讨论】:
-
如果您在 Google 上抓取搜索结果,那么无头浏览器 (imo) 是一种过于复杂的方法。考虑一个非 JavaScript 抓取工具,例如 Scrapy;如果没有客户端脚本,Google 也可以正常工作。更好的是,您可以使用 Google 搜索 API 吗?
-
感谢您的浏览。我实际上并没有抓取搜索结果,这就是为什么我不愿提及 Google 是域名的原因。我正在抓取 ajax 内容,所以我需要一些东西来加载 javascript。也就是说,一旦加载了内容,就没有理由继续使用 Selenium,所以我目前正在修改我的脚本,以便在页面加载后立即调用 webdriver 的
page_source方法,关闭驱动程序,然后解析源代码lxml. -
我正在抓取 ajax 内容,所以我需要一些东西来加载 JavaScript。 - 你能直接连接到这个 URL 吗?如果是这样,您可能不需要运行 JavaScript,除非响应实际上包含 JavaScript。如果它只包含 JSON/HTML/XML,并且 URL 的生成不需要 JavaScript,那么你可以使用 Scrapy。
-
好的,当然值得在每个请求之间延迟几秒钟,以防万一。
-
是的@halfer,在请求之间暂停最终解决了我的整个问题,尽管首先最小化请求非常有帮助。如果你把它放在一个答案中,我会接受它。
标签: python selenium-webdriver web-scraping vps headless-browser