web-dev-qa-db-ja.com

新しいタブでウェブを開くSelenium + Python

そのため、WebDriver内の新しいタブでWebサイトを開こうとしています。各Webサイトで新しいWebDriverを開くには、PhantomJSを使用して約3.5秒かかるため、これを行いたいと思います。

マルチプロセスpythonスクリプトを使用しています。各ページからいくつかの要素を取得したいので、ワークフローは次のようになります。

Open Browser

Loop throught my array
For element in array -> Open website in new tab -> do my business -> close it

しかし、私はこれを達成する方法を見つけることができません。

これが私が使用しているコードです。他のツールは許可されていますが、JavaScriptでロードされるWebサイトコンテンツを破棄するためのツール(ロード時にイベントがトリガーされたときに作成されるdivなど)をあまり知らないツールですセレンが必要な理由... BeautifulSoupは一部のページで使用できません。

#!/usr/bin/env python
import multiprocessing, time, pika, json, traceback, logging, sys, os, itertools, urllib, urllib2, cStringIO, mysql.connector, shutil, hashlib, socket, urllib2, re
from Selenium import webdriver
from Selenium.webdriver.common.keys import Keys
from PIL import Image
from os import listdir
from os.path import isfile, join
from bs4 import BeautifulSoup
from pprint import pprint

def getPhantomData(parameters):
    try:
        # We create WebDriver
        browser = webdriver.Firefox()
        # Navigate to URL
        browser.get(parameters['target_url'])
        # Find all links by Selector
        links = browser.find_elements_by_css_selector(parameters['selector'])

        result = []
        for link in links:
            # Extract link attribute and append to our list
            result.append(link.get_attribute(parameters['attribute']))
        browser.close()
        browser.quit()
        return json.dumps({'data': result})
    except Exception, err:
        browser.close()
        browser.quit()
        print err

def callback(ch, method, properties, body):
    parameters = json.loads(body)
    message = getPhantomData(parameters)

    if message['data']:
        ch.basic_ack(delivery_tag=method.delivery_tag)
    else:
        ch.basic_reject(delivery_tag=method.delivery_tag, requeue=True)

def consume():
    credentials = pika.PlainCredentials('invitado', 'invitado')
    rabbit = pika.ConnectionParameters('localhost',5672,'/',credentials)
    connection = pika.BlockingConnection(rabbit)
    channel = connection.channel()

    # Conectamos al canal
    channel.queue_declare(queue='com.stuff.images', durable=True)
    channel.basic_consume(callback,queue='com.stuff.images')

    print ' [*] Waiting for messages. To exit press CTRL^C'
    try:
        channel.start_consuming()
    except KeyboardInterrupt:
        pass

workers = 5
pool = multiprocessing.Pool(processes=workers)
for i in xrange(0, workers):
    pool.apply_async(consume)

try:
    while True:
        continue
except KeyboardInterrupt:
    print ' [*] Exiting...'
    pool.terminate()
    pool.join()
18

キーの組み合わせでタブの開閉を実現できます COMMAND + T または COMMAND + W (OSX)。他のOSでは使用できます CONTROL + T / CONTROL + W

Seleniumでは、このような動作をエミュレートできます。 1つのWebドライバーと、必要なテストと同じ数のタブを作成する必要があります。

これがコードです。

from Selenium import webdriver
from Selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("http://www.google.com/")

#open tab
driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') 
# You can use (Keys.CONTROL + 't') on other OSs

# Load a page 
driver.get('http://stackoverflow.com/')
# Make the tests...

# close the tab
# (Keys.CONTROL + 'w') on other OSs.
driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 'w') 


driver.close()
28
aberna

これは、別の例から適応した一般的なコードです。

from Selenium import webdriver
from Selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("http://www.google.com/")

#open tab
# ... take the code from the options below

# Load a page 
driver.get('http://bings.com')
# Make the tests...

# close the tab
driver.quit()

可能な方法は次のとおりです。

  1. 送信 <CTRL> + <T> 1つの要素に

    #open tab
    driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
    
  2. 送信 <CTRL> + <T>アクションチェーン経由

    ActionChains(driver).key_down(Keys.CONTROL).send_keys('t').key_up(Keys.CONTROL).perform()
    
  3. JavaScriptスニペットを実行する

    driver.execute_script('''window.open("http://bings.com","_blank");''')
    

    これを実現するには、設定 browser.link.open_newwindow および browser.link.open_newwindow.restriction が適切に設定されていることを確認する必要があります。最新バージョンのデフォルト値は大丈夫です。それ以外の場合は、おそらく次のものが必要です。

    fp = webdriver.FirefoxProfile()
    fp.set_preference("browser.link.open_newwindow", 3)
    fp.set_preference("browser.link.open_newwindow.restriction", 2)
    
    driver = webdriver.Firefox(browser_profile=fp)
    

    問題は、これらの設定が その他の値 にプリセットされており、frozen少なくともSelenium 3.4.0であることです。プロファイルを使用してJavaバインディングで設定する場合、 exception があり、pythonバインディングで新しい値は無視されます。

    Javaでは、geckodriverと通信するときにプロファイルオブジェクトを指定せずにこれらの設定を設定する方法がありますが、 pythonバインディングでまだ実装されていない:

    FirefoxOptions options = new FirefoxOptions().setProfile(fp);
    options.addPreference("browser.link.open_newwindow", 3);
    options.addPreference("browser.link.open_newwindow.restriction", 2);
    FirefoxDriver driver = new FirefoxDriver(options);
    

3番目のオプションは 動作を停止 for python Selenium 3.4.0でした。

最初の2つのオプションも、Selenium 3.4.0では work stop のようでした。 CTRLキーイベントを要素に送信することに依存しています。一見するとCTRLキーの問題のように見えますが、新しい Firefoxのマルチプロセス機能 のために失敗しています。この新しいアーキテクチャは、それを行うための新しい方法を課しているのかもしれませんし、一時的な実装の問題かもしれません。とにかく次の方法で無効にできます:

fp = webdriver.FirefoxProfile()
fp.set_preference("browser.tabs.remote.autostart", False)
fp.set_preference("browser.tabs.remote.autostart.1", False)
fp.set_preference("browser.tabs.remote.autostart.2", False)

driver = webdriver.Firefox(browser_profile=fp)

...そして、最初の方法で正常に使用できます。

16
yucer
browser.execute_script('''window.open("http://bings.com","_blank");''')

ブラウザwebDriverです

13

議論の中で、サイモンは次のことを明確に述べました

ハンドルのリストを格納するために使用されるデータ型は挿入によって順序付けられますが、WebDriver実装がウィンドウハンドルを反復して挿入する順序は、安定している必要はありません。順序は任意です。


Selenium v​​3.xを使用して、New TabからPythonがはるかに簡単になりました。 number_of_windows_to_be(2)WebDriverWaitを誘導し、新しいタブ/ウィンドウを開いて最終的に反復するたびにウィンドウハンドルを収集する必要があります。必要に応じて、ウィンドウハンドルとswitchTo().window(newly_opened)を使用します。開くことができるソリューションは次のとおりですhttp://www.google.co.in ininitial TABおよびhttps://www.yahoo.com隣接するTAB

  • コードブロック:

    from Selenium import webdriver
    from Selenium.webdriver.support.ui import WebDriverWait
    from Selenium.webdriver.support import expected_conditions as EC
    
    options = webdriver.ChromeOptions() 
    options.add_argument("start-maximized")
    options.add_argument('disable-infobars')
    driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
    driver.get("http://www.google.co.in")
    print("Initial Page Title is : %s" %driver.title)
    windows_before  = driver.current_window_handle
    print("First Window Handle is : %s" %windows_before)
    driver.execute_script("window.open('https://www.yahoo.com')")
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
    windows_after = driver.window_handles
    new_window = [x for x in windows_after if x != windows_before][0]
    driver.switch_to_window(new_window)
    print("Page Title after Tab Switching is : %s" %driver.title)
    print("Second Window Handle is : %s" %new_window)
    
  • コンソール出力:

    Initial Page Title is : Google
    First Window Handle is : CDwindow-B2B3DE3A222B3DA5237840FA574AF780
    Page Title after Tab Switching is : Yahoo
    Second Window Handle is : CDwindow-D7DA7666A0008ED91991C623105A2EC4
    
  • ブラウザのスナップショット:

multiple__tabs


アウトロ

Java ベースの議論は Seleniumを使用してWindowHandlesを使用してタブとウィンドウを追跡および反復する最良の方法 にあります。

5
DebanjanB

非常に長い間苦労した後、以下の方法が私のために働いた:

driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + Keys.TAB)

windows = driver.window_handles

time.sleep(3)
driver.switch_to.window(windows[1])
3
Ziad abbas