Selenium - 如何从iframe内部发送jQuery?

时间:2018-05-09 03:09:34

标签: python jquery json selenium

我一直在使用Selenium Webdriver for Python来自动执行我的工作中的一些日常任务。想要了解更多信息,我一直在使用Selenium在业余时间编写一些脚本。我已经取得了一些成功,但最近,在尝试为neopets.com制作机器人以进行日常活动时,我遇到了一个我无法在自动化方面获得任何牵引力的情景。

迷你游戏基本上只是一个随机确定的老虎机游戏,名为Trudy的惊喜(网址:http://www.neopets.com/trudys_surprise.phtml,您可能需要创建一个帐户才能访问它)。我想要完成的功能就是单击Selenium的“播放”按钮,或以其他方式执行插槽游戏。虽然这个功能非常简单,但在我看来(可能是因为我无法自行解决)这里有学习经验,因为解决方案并不像使用webelem.click()那样简单。告诉。

我一直在使用Chrome的Inspect功能来查看游戏的底层脚本。如果您导航到老虎机游戏,请右键单击游戏框架中的任意位置,然后单击“检查”控制台应显示突出显示的<canvas>元素。此<canvas>元素位于<iframe>内,我将在本文中引用该内容。

所以这就是我面临的问题(我试过的AKA事情不起作用):

我无法获得该按钮的xpath,因为游戏本身位于iframe内。我尝试使用driver.switch_to.frame()函数浏览iframe中所有元素的列表,然后执行driver.find_elements_by_xpath("//*"),并且只找到页面中描述的html元素(没有开始按钮)。

由于我找不到该元素,我想我会尝试复制它的效果。老虎机的源脚本位于http://www.neopets.com/trudydaily/js/slotsgame.js?v=1525633042。我会在这里复制它,但它很长。我几乎没有使用html或Javascript的经验,但似乎这个脚本是在iframe的标题中调用的

<script src="/trudydaily/js/slotsgame.js?v=1525633042">
</script>

创建一个SlotsGame对象,然后由iframe主体中的脚本调用。 SlotsGame对象只有三个可调用的成员函数:Initialize,LoadAssets和Start。它看起来像脚本发布jQuery并等待来自服务器的响应,允许用户根据响应旋转或不旋转。调用SlotsGame对象的脚本看起来像

  var ajaxurl = '/trudydaily/ajax/claimprize.php';
  //var data = {'action': 'getslotstate'};
  var data = {
    'action': 'getslotstate','key': '2nA6BqsTIM1IT785Di08dqyFKnLCM1M7VTcOfSnC41I%3D'};
  var resp;
  parent.$.post(ajaxurl, data, function (response){
    resp = JSON.parse(response);
                if(resp.error == ""){
          SlotsGame.LoadAssets(AssetLoadComplete, "http://images.neopets.com");
        }
      else{
        parent.CloseSlotsGame();
      }
            }
    );
    SlotsGame.Initialize();
    function AssetLoadComplete(){
      SlotsGame.Start(resp);
    }
    function CloseGame(){
      parent.CloseSlotsGame();
    };

每次加载页面时key值都会更改。

来自driver.execute_script("SlotsGame.LoadAssets()")...Initialize()...的呼叫都可以在iframe的上下文中调用(他们在iframe中创建了一个插槽游戏的副本),所以我知道我在正确的轨道上。但是,我尝试在iframe的上下文中执行SlotsGame.Start(i) i=1,2,3而不是骰子(或不是插槽)。我也尝试使用driver.execute_script(webelem.get_attribute('innerHTML'))执行整个上述脚本,但没有任何反应。

我确信我错过了一种自动激活这台机器的简单方法,但我已经尝试了几乎所有我能想到的但没有成功。

对于任何不精确的术语或类似的道歉,我仍然试图选择这个技能。我希望了解html,Javascript和JSON的人会理解这个问题。如果您能想出我可以编辑问题的方式,请告诉我,以使其更精确或更普遍适用。提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

如果只有Selenium可以简化发布请求,这将非常简单。幸运的是,有一个软件包! https://github.com/cryzed/Selenium-Requests

import re
import time
from seleniumrequests import Firefox
from selenium.webdriver.support.ui import WebDriverWait as wait

# Selenium-Requests way of launching a browser instance
browser = Firefox()

然后在您登录后,

browser.get("http://www.neopets.com/trudys_surprise.phtml")     

# Waits for trudys iframe to be loaded, and then switches to the iframe
wait(browser, 10).until(EC.frame_to_be_available_and_switch_to_it("frameTest"))
time.sleep(1)

# gets key from the iframe page_source; not the worlds best regex   
matchobj = re.search(r"\'action\'\: \'\w*\',\'key\'\: \'(.*)\'\}\;", str(browser.page_source))

if(matchobj):
    key = str(matchobj.group(1))    
    postPage = ('http://www.neopets.com/trudydaily/ajax/claimprize.php')

    response = browser.request('POST', postPage, data={'action':'getslotstate','key':key})
    time.sleep(2)

    response = browser.request('POST', postPage, data={'action':'beginroll'})
    time.sleep(2)

    response = browser.request('POST', postPage, data={'action':'prizeclaimed'})
    time.sleep(2)   

    # switches back from the iframe to the main window
    browser.switch_to.default_content()