【问题标题】:Python Selenium causing error when screenshotting when running headlessPython Selenium 在无头运行时截屏时导致错误
【发布时间】:2021-09-11 22:16:52
【问题描述】:

我有一个 selenium 应用程序,它做了一些工作,然后将图像的屏幕截图保存为 png:

img = driver.find_element_by_xpath('//div[@id="qrcode"]/img')

with open('image.png', 'wb') as f:
     f.write(img.screenshot_as_png)

然后会发短信给我。

在我引入 headless 之前,这一切都很好:

chrome_options = Options()
chrome_options.add_argument('--headless')

driver = webdriver.Chrome(executable_path="C:/chromedriver.exe", options=chrome_options)

现在,由于某种原因,它只保存了图像的上半部分。我把无头论点拿走了,它工作得很好。有什么建议吗?

【问题讨论】:

标签: selenium selenium-webdriver


【解决方案1】:

导致错误的不是屏幕截图。 headless浏览器的分辨率和普通浏览器简直是天壤之别。

您可以通过此命令手动调整 Selenium 驱动程序窗口大小。尝试更改size,看看是否可以获得全分辨率图像。

chrome_options.add_argument("window-size=1400,600")

你也可以试试:

chrome_options.add_argument("--start-maximized")

【讨论】:

    【解决方案2】:

    虽然@Hammad 解决方案似乎是一个合理的解决方案,但即使这不起作用并且您对请求模块感兴趣,您也可以尝试以下代码来截取屏幕截图。

    import requests
    
    path = 'target.jpg'
    response = requests.get("Image SRC/URL here", stream=True)
    
    if response.status_code == 200:
        with open(path, 'wb') as file:
            for pic in response:
                file.write(pic)
    

    这里也可以代替URL,可以通过

    img = driver.find_element_by_xpath('//div[@id="qrcode"]/img').get_attribute('src')

    【讨论】:

    • 这种方法的问题是我必须先通过一个登录过程才能进入带有二维码的页面。图片每天都会变化,所以我不能使用之前设置的链接。
    【解决方案3】:

    一些网站具有反抓取机制,涉及检测浏览器的webdriver 属性。当您为 Chrome 启用 headless 模式时,浏览器不会设置此属性。从而向网站表明请求的来源是通过机器人或程序。

    您可以尝试执行可以在无头模式下为您的浏览器设置webdriver 属性的javascript。

    不过,请注意,这只是网站用来检测机器人或程序的众多机制之一。

    您也可以查看answer

    这是我使用 pyppeteer 库编写的示例代码。

    导入异步
    从 pyppeteer 导入启动
    # from pyvirtualdisplay 导入显示
    从 argparse 导入 ArgumentParser
    
    
    HTMLRetriever 类(对象):
        _page_source = 无
        _title = 无
    
        def __init__(self, url):
            self.url = 网址
    
        异步默认加载(自我):
            # 使用 Display(backend='xvfb') 作为显示:
            等待 self._init_browser()
            等待 self._init_webpage()
            等待 self._connect_website()
            等待 self._take_snapshot()
    
        @classmethod
        异步定义_init_display(cls):
            cls.disp = 显示(后端='xvfb')
    
        @classmethod
        异步定义_init_browser(cls):
            cls.browser = 等待启动(headless=True, args=[
            “--无沙盒”,
            “--单进程”,
            “--禁用-开发-shm-使用”,
            “--无合子”,
            '--user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"'
        ])
    
        @classmethod
        异步定义_init_webpage(cls):
            cls.page = 等待 cls.browser.newPage()
            等待 asyncio.sleep(1)
            等待 cls.page.setJavaScriptEnabled(True)
    
        @classmethod
        异步定义_init_webpage_properties(cls):
            等待 cls.page.evaluate('''() =>{
                Object.defineProperties(导航器,{
                网络驱动程序:{
                    得到:()=>假
                    }
                })
            }''')
    
            等待 cls.page.evaluate('''() =>{
                Object.defineProperties(窗口,{
                铬合金:{
                    得到:()=>真
                    }
                })
            }''')
    
        async def _connect_website(self):
            等待 self.page.goto(self.url, {'waitUntil': 'networkidle2', 'timeout': 60000})
            等待 asyncio.sleep(6)
            self._title = 等待 self.page.evaluate('''() => {
                返回文档.title
            }''')
    
            self._page_source = 等待 self.page.content()
    
        async def _take_snapshot(self):
            await self.page.screenshot({'path': f"snapshots/{self.url.strip('https://').strip('http://').replace('.', '_' ).replace('/','-')}.png"})
    
        @财产
        def page_source(self):
            返回 self._page_source
    
        @财产
        定义标题(自我):
            返回自我._title
    
        异步定义关闭(自我):
            等待 self.browser.close()
    
    
    异步定义主():
        parser = ArgumentParser(description='获取网页 URL 的 HTMl 的工具')
        parser.add_argument('-u', '--url', dest='url', type=str, required=True, metavar='URL',
                            help='要检索 HTML 的网站的 URL')
        args = parser.parse_args()
        kwargs = 变量(参数)
        如果不是 kwargs.get('url') 为无:
            检索器 = HTMLRetriever(url=kwargs.get('url'))
            等待检索器.load()
            打印(retriever.title)
            等待检索器.close()
    
    如果 __name__ == '__main__':
        asyncio.get_event_loop().run_until_complete(main())

    【讨论】:

    • 我怀疑我从中获取信息的网站是否有反爬虫措施,原因有两个:1. 网站 ToS 对爬虫只字未提 2. 我在由同一网站运营的网站上做过类似的事情域没有任何问题
    猜你喜欢
    • 2021-10-24
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 2021-12-20
    • 1970-01-01
    • 2020-05-23
    • 2013-01-23
    相关资源
    最近更新 更多