Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ghost.py在代用JavaScript时的超时问题

ghost.py在代用JavaScript时的超时问题

作者头像
Masimaro
发布于 2018-08-31 07:50:14
发布于 2018-08-31 07:50:14
93800
代码可运行
举报
运行总次数:0
代码可运行

在写爬虫的时候,关于JavaScript的解析问题,我在网上找到的一个解决方案是使用ghost.py这个模块,他是一个基于webkit封装的一个客户端,可以用来解析动态页面。它的使用非常简单,它从2.x版本开始,变化就有点大了,在这我主要是针对他的1.0版本。 首先在GitHub上克隆它,然后在对应的文件中执行python setup.py install命令,这样就可以安装了,注意在这不要直接使用pip,使用pip会默认安装2.x版本。 安装完成后,可以编写如下代码来加载一个网页:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from ghost import Ghost
gh = Ghost(display = True, wait_timeout = 60)
page, res = gh.open(url)
for item in res:
    print item.url

这段代码可以打印在加载页面时,webkit向远程服务器请求了那些资源。对于AJAX请求来说,使用这个特性非常方便的就可以获取到对应的url 它在里面提供了一些特定的方法用来处理页面的事件,比如鼠标单击某个标签时调用click,通过阅读它的源代码可以知道针对这些事件的处理,它调用的是JavaScript代码,比如说click事件,click事件的源码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@client_utils_required
    @can_load_page
    def click(self, selector):
        """Click the targeted element.
        :param selector: A CSS3 selector to targeted element.
        """
        if not self.exists(selector):
            raise Exception("Can't find element to click")
        return self.evaluate('GhostUtils.click("%s");' % selector)

它上面的两个装饰器的代码分别如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def can_load_page(func):
    """Decorator that specifies if user can expect page loading from
    this action. If expect_loading is set to True, ghost will wait
    for page_loaded event.
    """
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        expect_loading = False
        if 'expect_loading' in kwargs:
            expect_loading = kwargs['expect_loading']
            del kwargs['expect_loading']
        if expect_loading:
            self.loaded = False
            func(self, *args, **kwargs)
            return self.wait_for_page_loaded()
        return func(self, *args, **kwargs)
    return wrapper

def client_utils_required(func):
    """Decorator that checks avabality of Ghost client side utils,
    injects require javascript file instead.
    """
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        if not self.global_exists('GhostUtils'):
            self.evaluate_js_file(
                os.path.join(os.path.dirname(__file__), 'utils.js'))
        return func(self, *args, **kwargs)
    return wrapper

函数can_load_page是用来判断用户是否需要进行等待,等待的条件是页面加载完毕,在阅读它的源代码时可以知道,它自身给webkit注册了几个槽函数,一个用来处理页面开始加载的信息,一个用来处理页面加载结束的信息,在加载时将一个bool变量设置为true,加载结束时设置为false,另外在返回前调用等待函数,等待函数主要判断这个bool变量是否为false,为false则返回,否则就继续循环。这样当页面加载完毕后,就可以返回,同样的,这个can_load_page函数就是在执行JavaScript期间进行等待。直到页面加载完成后返回(当然,是否需要等待就看我们是否传入expect_load这个参数了,它默认是False,即不等待) client_utils_required函数主要负责读取utils.js这个文件中的JavaScript代码并执行它,这个文件中代码都是函数,在这所谓的执行只是为了将其加载到内存,准备随时调用。 根据以上所说,大概能组织一下执行click函数时经历的步骤了:首先会调用client_utils_required函数,将对应的JavaScript函数代码加载起来,然后判断是否需要等待,如果需要等待将设置对应等待变量的值,然后真正调用对应的JavaScript函数来进行元素的点击,然后调用等待函数,如果需要等待,则会等待到新页面加载,否则直接返回,这样就完成了一个点击事件。根据这些我们扩展它的功能,从click函数的定义来看,它需要传入一个css选择器,但是我遇到的场景是我希望通过JavaScript得到的页面的dom元素,根据它的下标来进行点击,比如说

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
document.getElementsByTagName("a")[3];

我通过上面的代码获取到了这个元素,我现在要点击这个元素,自然不能直接调用click函数,ghost中也没有对应的函数可以使用,这个时候就需要我们进行扩展。当时我给出的代码入下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@client_utils_required
@can_load_page
def js_click(self, jscontent): #jscontent使用js来定位元素的代码
    return self.evaluate('GhostUtils.jsclick("%s");' % jscontent);

然后来扩展utils.js文件,在里面新加一个对应的函数jsclick

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
jsclick: function(jscontent) {
        var elem = eval(jscontent);
        if (!elem) {
            return false;
        }
        var evt = document.createEvent("MouseEvents");
        evt.initMouseEvent("click", true, true, window, 1, 1, 1, 1, 1,
            false, false, false, false, 0, elem);
        if (elem.dispatchEvent(evt)) {
            return true;
        }
        return false;
    }

但是我在这发现,它可以调用成功的点击,但是超时率比较高,几乎达到了70%以上,这个问题一直使我困惑,后来我仔细阅读源代码后发现,问题出在expect_loading = True,也就是让其等待页面加载完毕。有很多页面都是使用AJAX技术的,它只是改变页面的状态而不会重新加载,这样自然那个等待函数不会返回,当时间一到自然也就超时了,但是如果不加这个参数,让他立即返回,那么我们就得不到请求的url,而在webkit中也没有办法判断一个JavaScript代码是否执行完毕,所以在这我采取了一个折中的方案,每次等待1s,所以将上面的jsclick函数改为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@client_utils_required
def js_click(self, jscontent): #jscontent使用js来定位元素的代码
    return self.main_frame.evaluateJavaScript('GhostUtils.jsclick("%s");' % jscontent); #执行js函数
    for i in range(0, 100):
        time.sleep(0.01)
           Ghost._app.processEvents() #在等待的时候让QT的信号槽机制仍然运转

这样可能会有一定的性能损失,但是目前我只能想到这个方案。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-10-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python中ghost的使用
ghost.py is a webkit web client written in python.
py3study
2020/01/10
1.3K0
[1291]Playwright教程
这种类型的python库有好多种,鼎鼎大名的selenium,还有playwright、Pyppeteer等。
周小董
2024/12/20
7070
[1291]Playwright教程
强大易用!新一代爬虫利器 Playwright 的介绍
Playwright 是微软在 2020 年初开源的新一代自动化测试工具,它的功能类似于 Selenium、Pyppeteer 等,都可以驱动浏览器进行各种自动化操作。它的功能也非常强大,对市面上的主流浏览器都提供了支持,API 功能简洁又强大。虽然诞生比较晚,但是现在发展得非常火热。
崔庆才
2021/12/10
7.3K0
强大易用!新一代爬虫利器 Playwright 的介绍
比Selenium更优秀的playwright介绍与未来展望
Playwright是微软开发的,专门为满足端到端测试需求而创建的。Playwright支持包括Chromium、WebKit和Firefox在内的所有现代渲染引擎。在Windows、Linux和macOS上进行测试,本地或在CI上,无头或有头,带有本机移动仿真。
JadePeng
2024/05/16
5390
比Selenium更优秀的playwright介绍与未来展望
【腾讯云 Cloud Studio 实战训练营】沉浸式体验编写一个博客系统
欢迎参加腾讯云 Cloud Studio 实战训练营!在本次训练营中,我们将通过沉浸式体验,带您一步步编写一个基于 Nuxt.js 的静态博客系统。无论您是初学者还是有一定编程经验的开发者,本训练营都将为您提供一个深入了解和掌握 Nuxt.js 技术以及静态网站开发的机会。
全栈若城
2023/08/15
4390
Playwright: 比 Puppeteer 更好用的浏览器自动化工具
在 Playwright 之前,我一般会使用 Selenium 或者 Puppeteer 来进行浏览器自动化操作。然而,Selenium 经常会有一些奇怪的 bug, Puppeteer 则是没有官方 Python 版,非官方版本也只有 async 版本,并且也是有一些奇怪的 bug. 另外,众所周知,Python 的 Async API 并不是那么好使。
爬虫技术学习
2023/03/06
3.5K0
Playwright: 比 Puppeteer 更好用的浏览器自动化工具
React 应用架构实战 0x7:测试
在这一节中,我们将学习如何使用不同的测试方法来测试我们的应用程序。这将使我们有信心对应用程序进行重构、构建新功能和修改现有功能,而不用担心破坏当前的应用程序行为。
Cellinlab
2023/05/17
1.7K0
Playwright 入门教程
在当前工作目录或子目录内部,创建 test_my_application.py 文件,其内容如下:
小阑本阑
2023/06/27
7680
Playwright 入门教程
playwright
一、page_func.py # coding=utf-8 """ @Project :playwright_test @File :page_func.py @Author :gaojs @Date :2022/7/14 21:48 @Blogs : https://www.gaojs.com.cn """ import time import playwright from playwright.sync_api import Playwr
懿曲折扇情
2022/08/24
6440
腾讯云上PhantomJS用法示例
崔庆才
2017/04/06
3.3K0
腾讯云上PhantomJS用法示例
ChatGPT与基于GUI的自动化测试
当使用Edge浏览器结合Selenium框架生成百度查询测试代码时,你可以使用以下Python代码示例:
顾翔
2024/09/10
2140
ChatGPT与基于GUI的自动化测试
[Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
最近在使用Python爬取网页内容时,总是遇到JS临时加载、动态获取网页信息的困难。例如爬取CSDN下载资源评论、搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题。这第一篇文章当然就是安装过程及入门介绍。
统计学家
2019/04/10
1.1K0
[Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
微软自动化神器playwright
https://www.bilibili.com/video/BV14B4y1z7Ev
懿曲折扇情
2022/08/24
3.2K1
微软自动化神器playwright
Vue3组件库工程化实战 --Element3
随着对前端功能和性能的不断提高,前端早就不是一段内嵌于页面的一段JS代码了。已经进化为一个系统复杂的工程了。 下面我就结合element3组件库的搭建经验。带大家搭建一个mini版组件库。
@超人
2021/03/18
1.4K0
Vue3组件库工程化实战 --Element3
Scrapy框架的使用之Scrapy对接Selenium
Scrapy抓取页面的方式和requests库类似,都是直接模拟HTTP请求,而Scrapy也不能抓取JavaScript动态渲染的页面。在前文中抓取JavaScript渲染的页面有两种方式。一种是分析Ajax请求,找到其对应的接口抓取,Scrapy同样可以用此种方式抓取。另一种是直接用Selenium或Splash模拟浏览器进行抓取,我们不需要关心页面后台发生的请求,也不需要分析渲染过程,只需要关心页面最终结果即可,可见即可爬。那么,如果Scrapy可以对接Selenium,那Scrapy就可以处理任何
崔庆才
2018/06/25
2.5K0
Scrapy 对接 Selenium
Scrapy抓取页面的方式和Requests库类似,都是直接模拟HTTP请求,因此如果遇到JavaScript渲染的页面Scrapy同样是无法抓取的,而在前文中我们抓取JavaScript渲染的页面有
崔庆才
2017/08/08
6.6K0
Scrapy 对接 Selenium
【教程】新的Selenium!整合了隐藏浏览器指纹等功能
GitHub - seleniumbase/SeleniumBase📊 Python's all-in-one framework for web crawling, scraping, testing, and reporting. Supports pytest. UC Mode provides stealth. Includes many tools. - seleniumbase/SeleniumBase
小锋学长生活大爆炸
2024/07/15
9010
h5中performance.timing轻松获取网页各个数据 如dom加载时间 渲染时长 加载完触发时间
在控制台中输入window.performance.timing(html5的属性);
一个会写诗的程序员
2018/08/17
3.8K0
爬虫最终杀手锏 — PhantomJS 详解(附案例)
Selenium: 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 Phantomjs 的工具代替真实的浏览器。
全栈程序员站长
2022/09/06
2.3K0
腾讯云上Selenium用法示例
崔庆才
2017/04/06
3.8K0
腾讯云上Selenium用法示例
相关推荐
Python中ghost的使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验