【问题标题】:Check for the google maps spelling of a location's name检查位置名称的谷歌地图拼写
【发布时间】:2017-03-31 23:45:51
【问题描述】:

我想用谷歌地图获取欧洲一些机场之间的旅行时间。问题是名称的某些拼写不准确,因此,我想先检查名称是否错误并获取 google 的名称版本。从这个question,我可以使用selenium 来做到这一点,但我的代码有一些问题,1)输出并不总是完整的,(最后两个结果只有一个字母)2)它在最后抛出一个异常列表(见下文)。请帮我修复代码。自动化这是唯一的方法,因为机场列表很长。

输入:

wronglySpelled = ['Treviso (San Angelo) Airport', 'Milano - Malpensa
       Airport', 'Venezia - Tessera Airport', 'Milano - Linate Airport',
       'Treviso (San Angelo) Airport', 'Treviso (San Angelo) Airport',
      'Milano - Malpensa Airport', 'Venezia - Tessera Airport', 'Guernsey
       Channel Is. Airport', 'Jersey Channel Is. Airport','Treviso (San
                     Angelo) Airport']

代码:

def setup():
    driver = webdriver.Chrome()
    driver.get("http://maps.google.com")
    driver.maximize_window() # For maximizing window
    driver.implicitly_wait(20) # gives an implicit wait for 20 seconds
    return driver

def correct_name(driver, name_to_check):
    searchBox = driver.find_element_by_name('q')
    searchBox.send_keys(name_to_check)
    correct_name = driver.find_element_by_class_name('suggest-bold')
    return correct_name.text.encode('utf-8')

driver = setup()
for item in wronglySpelled:
    print item,':', correct_name(driver, item)
    time.sleep(5)
    driver.find_element_by_id('searchboxinput').clear()
driver.quit()

错误信息:

Traceback (most recent call last):
  File "C:/...", line 60, in <module>
    print item,':', correct_name(driver, item)
  File "C:/...", line 41, in correct_name
    correct_name = driver.find_element_by_class_name('suggest-bold')
  File "C:\...", line 415, in find_element_by_class_name
    return self.find_element(by=By.CLASS_NAME, value=name)
  File "C:\...", line 756, in find_element
    'value': value})['value']
  File "C:\...", line 238, in execute
    self.error_handler.check_response(response)
  File "C:\...", line 193, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"class name","selector":"suggest-bold"}
  (Session info: chrome=56.0.2924.87)
  (Driver info: chromedriver=2.28.455520 (cc17746adff54984afff480136733114c6b3704b),platform=Windows NT 10.0.14393 x86_64)

输出:

## Formatted as Input name : Google maps version
Treviso (San Angelo) Airport : Aeroporto di Treviso Canova
Milano - Malpensa Airport : Milano Malpensa Airport
Venezia - Tessera Airport : Venice Marco Polo Airport
Milano - Linate Airport : Aeroporto Milano Linate
Treviso (San Angelo) Airport : Aeroporto di Treviso Canova
Treviso (San Angelo) Airport : Aeroporto di Treviso Canova
Milano - Malpensa Airport : m
Venezia - Tessera Airport : V
Guernsey Channel Is. Airport :

【问题讨论】:

  • 您应该使用 google maps api。它应该无限快,等等。
  • 当您的脚本在字段中输入Guernsey Channel Is. Airport 时,Google 没有任何建议。因此,DOM 中永远不会有一个类名为 suggest-bold 的元素,而这又会抛出您所看到的 NoSuchElementException
  • @LeviNoecker 对返回 mMilano - Malpensa Airport 有何解释?

标签: python google-maps selenium


【解决方案1】:

正如@JeffC 在他的评论中提到的那样,您最好使用 Google Maps API 来完成您想要做的任何事情。

脚本中的几件事:

  • 我发现隐式等待几乎毫无价值。在我看来,花时间了解显式等待、它们如何工作以及何时有用是值得的。由于 Google 倾向于在其大量信息中使用 AJAX 的高度动态网站,因此如果您使用显式等待,则地图之类的功能往往效果最佳。
  • 您的脚本抛出了 NoSuchElementException,因为 Google 没有对该词的建议,因此您的搜索词 suggest-bold 从未匹配任何内容。通常,当我看到一个危险信号 NSEE 时,我需要重新评估我的搜索方式
  • 我认为,但我不肯定,Milano - Malpensa Airport : m 输出是硒在元素完全加载之前从元素中收集文本的结果。
  • 我个人不惜一切代价避免硬睡 (time.sleep(5)),因为如果您遇到任何网络延迟,它们很容易导致您的脚本中断。这是显式等待的另一个亮点,因为他们可以尝试并尝试找到一个元素,直到它实际加载,然后继续。

也就是说,我会这样做:

from explicit import waiter, ID
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait as Wait
from selenium.common.exceptions import StaleElementReferenceException

NO_SUGGESTION = 'Add a missing place to Google Maps.'

original_names = [
    'Treviso (San Angelo) Airport',
    'Milano - Malpensa Airport',
    'Venezia - Tessera Airport',
    'Milano - Linate Airport',
    'Treviso (San Angelo) Airport',
    'Treviso (San Angelo) Airport',
    'Milano - Malpensa Airport',
    'Venezia - Tessera Airport',
    'Guernsey Channel Is. Airport',
    'Jersey Channel Is. Airport',
    'Treviso (San Angelo) Airport'
]


def get_name_suggestion(driver, name):
    # Find the search box, clear it, write the name
    waiter.find_write(driver, 'searchboxinput', name, by=ID, clear_first=True)

    class SuggestionLoads(object):
        def __init__(self):
            self._last_seen = None

        def __call__(self, driver):
            """ Custom expected condition.
                Returns either the first suggested name, or '<No Suggestion>'
                Raises a TimeoutException in the event the page source is different
            """
            suggestion_icon = 'div.suggest-icon-container'
            suggest_css = 'div.suggest-left-cell > span.suggest-query'
            try:

                # Only want suggestions that have the location icon next to them, and not the
                # magnifying glass. Return False if we don't find any so as to retry
                icons = driver.find_elements_by_css_selector(suggestion_icon)
                if len(icons) < 1:
                    return False

                elems = driver.find_elements_by_css_selector(suggest_css)

                if len(elems) == 0:
                    # No suggestions have loaded yet, return False so the Wait can retry
                    return False

                suggest_text = elems[0].text
                if len(suggest_text) == 1:
                    # Sometimes we catch text mid-update. Return False to retry
                    # and hopefully get the whole suggestion
                    return False
                elif suggest_text == NO_SUGGESTION:
                    # Google has no suggestion for us, return NO_SUGGESTION, which the Wait will
                    # evaluate as True and exit
                    return '<No Suggestion>'
                else:
                    # We found a valid suggestion. We need to make sure nothing else is going to
                    # get AJAXed in, so compare it to or _last_seen property. If they match,
                    # everything has stabilized and return the string, which will be evaluated as
                    # True and cause the Wait to exit
                    # If you don't do this, you wind up with jung suggestions like "Traffic"
                    if suggest_text == self._last_seen:
                        return suggest_text
                    else:
                        self._last_seen = suggest_text
                        return False

            except StaleElementReferenceException:
                # Because the DOM is constantly updating, there is a pretty decent chance that a
                # SERE will get thrown. Catch it if it does and return False so the Wait
                # can try again
                return False

    return Wait(driver, 30).until(SuggestionLoads())


def main():
    driver = webdriver.Chrome()
    try:
        driver.get("http://maps.google.com")
        driver.maximize_window()
        for orig_name in original_names:
            suggested_name = get_name_suggestion(driver, orig_name)
            print "{0}: {1}".format(orig_name, suggested_name)
    finally:  # This is useful to make sure the browsers get closed, even if an exception is thrown
        driver.quit()


if __name__ == "__main__":
    main()

返回:

 (.venv27) ➜  tmp python google_maps.py
 Treviso (San Angelo) Airport: Aeroporto di Treviso Canova
 Milano - Malpensa Airport: Milano Malpensa Airport
 Venezia - Tessera Airport: Venice Marco Polo Airport
 Milano - Linate Airport: Aeroporto Milano Linate
 Treviso (San Angelo) Airport: Aeroporto di Treviso Canova
 Treviso (San Angelo) Airport: Aeroporto di Treviso Canova
 Milano - Malpensa Airport: Milano Malpensa Airport
 Venezia - Tessera Airport: Venice Marco Polo Airport
 Guernsey Channel Is. Airport: <No Suggestion>
 Jersey Channel Is. Airport: <No Suggestion>
 Treviso (San Angelo) Airport: Aeroporto di Treviso Canova

完整披露者:explicit 是我维护的一个库,可从 PyPI:pip install explicit 获得。它旨在使使用显式等待更容易,但您可以将其替换为花园式等待

【讨论】:

  • 感谢您对我的代码和您的解决方案的详细分析。这非常有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 2013-04-15
  • 2014-10-30
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多