如何返回 selenium 浏览器(或如何导入返回 selenium 浏览器的 def)

Posted

技术标签:

【中文标题】如何返回 selenium 浏览器(或如何导入返回 selenium 浏览器的 def)【英文标题】:How to return selenium browser (or how to import a def that return selenium browser) 【发布时间】:2018-06-06 18:19:39 【问题描述】:

我想在一个函数中启动一个带有特定设置(privoxy、Tor、randon 用户代理...)的 selenium 浏览器,然后在我的代码中调用这个函数。我创建了一个 python 脚本mybrowser.py,里面有这个:

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from fake_useragent import UserAgent
from stem import Signal
from stem.control import Controller

class MyBrowserClass:
    def start_browser():
        service_args = [
            '--proxy=127.0.0.1:8118',
            '--proxy-type= http',
            ]
        dcap = dict(DesiredCapabilities.PHANTOMJS)
        dcap["phantomjs.page.settings.userAgent"] = (UserAgent().random)

        browser = webdriver.PhantomJS(service_args = service_args,         desired_capabilities=dcap)
        return browser

    def set_new_ip():
        with Controller.from_port(port=9051) as controller:
            controller.authenticate(password=password) 
            controller.signal(Signal.NEWNYM)

然后我将它导入另一个脚本myscraping.py,里面有这个:

import mybrowser
import time

browser= mybrowser.MyBrowserClass.start_browser()
browser.get("https://canihazip.com/s")
print(browser.page_source)
mybrowser.MyBrowserClass.set_new_ip()
time.sleep(12) 
browser.get("https://canihazip.com/s")
print(browser.page_source)

浏览器正在工作 - 我可以访问该页面并使用 .page_source 检索它。

但 IP 在第一次和第二次打印之间没有变化。如果我在myscraping.py 中移动函数的内容(并删除导入+函数调用),那么 IP 会改变。

为什么?返回浏览器有问题吗?我该如何解决这个问题?


实际上,情况要复杂一些。当我在调用mybrowser.set_new_ip()wait of 12 sec(参见下面的行)之前和之后连接到https://check.torproject.org 时,网页提供的IP 在第一次和第二次调用之间发生变化。所以我的 IP 发生了变化(根据 Tor),但 https://httpbin.org/ipicanhazip.com 都没有检测到 IP 的变化。

...
browser.get("https://canihazip.com/s")
print(browser.page_source)
browser.get("https://check.torproject.org/")
print(browser.find_element_by_xpath('//div[@class="content"]').text )
mybrowser.set_new_ip()
time.sleep(12) 
browser.get("https://check.torproject.org/")
print(browser.find_element_by_xpath('//div[@class="content"]').text )
browser.get("https://canihazip.com/s")
print(browser.page_source)

所以打印出来的IP是这样的:

42.38.215.198 (canihazip before mybrowser.set_new_ip() )
42.38.215.198  (check.torproject before mybrowser.set_new_ip() )
106.184.130.30  (check.torproject after mybrowser.set_new_ip() )
42.38.215.198 (canihazip after  mybrowser.set_new_ip())

Privoxy 配置:在C:\Program Files (x86)\Privoxy\config.txt 中,我取消了对这一行的注释(9050 是 Tor 使用的端口):

forward-socks5t   /               127.0.0.1:9050 

Tor 配置:在torcc,我有这个:

ControlPort 9051
HashedControlPassword : xxxx

【问题讨论】:

browser.refresh()browser.get("https://canihazip.com/s") 之后是否影响报告的IP? browser.refresh() 不影响结果(我在browser.get("https://canihazip.com/s") 之后尝试过,也只是在mybrowser.set_new_ip() 之后尝试过)。 好的,如何重新创建浏览器实例 - browser.close(),然后再次创建 browser= mybrowser.start_browser()browser.get("https://canihazip.com/s") 另外,如果可能,请发布您的 privoxy+tor 配置。谢谢。 这个问题的标题并不代表真正的问题。 【参考方案1】:

可能是因为 PhantomJS 保留了请求内容的内存缓存。因此,您使用 PhantomJS 浏览器的第一次访问可能会产生动态结果,但该结果随后会被缓存,并且每次连续访问都会使用该缓存页面。

这个内存缓存导致了CSRF-Token在刷新时没有改变等问题,现在我相信这是你问题的根本原因。 issue 于 2013 年提出并解决,但解决方案是一种方法,clearMemoryCache,在 PhantomJS 的 WebPage 类中找到。遗憾的是,我们正在处理 Selenium webdriver.PhantomJS 实例。

因此,除非我在监督某些事情,否则很难通过 Selenium 的抽象来访问此方法。

我认为唯一合适的解决方案是使用另一个没有像 PhantomJS 那样的 内存缓存 的 webdriver。我已经使用 Chrome 对其进行了测试,并且效果很好:

103.***.**.***
72.***.***.***

另外,作为旁注,Selenium 正在逐步淘汰 PhantomJS:

UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead

【讨论】:

【参考方案2】:

您可能需要检查是否有新的 nym。

is_newnym_available - 如果 tor 当前接受 NEWNYM 信号则为真

if controller.is_newnym_available(): controller.signal(Signal.NEWNYM)

【讨论】:

以上是关于如何返回 selenium 浏览器(或如何导入返回 selenium 浏览器的 def)的主要内容,如果未能解决你的问题,请参考以下文章

Selenium Webdriver如何触发HTTP请求

如何在断言 Selenium getCssValue("background") 返回的背景颜色 rgb(255,255,255) 时将 #ffffff 转换为 #fff 或 #f

如何将 CSV 数据导入多个数组并通过 VBA 中的函数或子函数返回多个数组?

Selenium 解析 - 如何按一个类查找元素并返回另一个类

如何解决Python selenium webdriver返回空白文件

Java+Selenium 如何实现关闭当前窗口并返回上一个窗口-driver.close()