Python3 Selenium问题

时间:2019-03-15 15:32:55

标签: python-3.x selenium

我想通过Web page抓取一些评论。当我尝试通过Selenium选择转到按钮(转到下一页)时,它始终显示一个弹出窗口。我尝试使用Selenium关闭弹出窗口,但仍然无法正常工作。有人可以帮助我解决此问题并帮助我完成下面的next_page()函数吗?非常感谢!

我已经完成了功能 scrap_comments()。我要做的是完成功能 next_page()

这是我的代码。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By

# url
url = "https://hotels.ctrip.com/hotel/347422.html?isFull=F#ctm_ref=hod_sr_lst_dl_n_1_8"

# User Agent
User_Agent_List = ["Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2",
                   "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
                   "Mozilla/5.0 (compatible; MSIE 10.0; Macintosh; Intel Mac OS X 10_7_3; Trident/6.0)",
                   "Opera/9.80 (X11; Linux i686; U; ru) Presto/2.8.131 Version/11.11",
                   "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2",
                   "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1",
                   "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25"]

# Define the related lists
Score = []
Travel_Types = []
Room_Types = []
Travel_Dates = []
Comments = []

DEFINE_PAGE = 10

def next_page():
    """
    It is a function to execute Next Page function
    """
    current_page = int(browser.find_element_by_css_selector('a.current').text)

    # First, clear the input box
    browser.find_element_by_id("cPageNum").clear()
    print('Clear the input page')

    # Second, input the next page
    nextPage = current_page + 1
    print('Next page ',nextPage)
    browser.find_element_by_id("cPageNum").send_keys(nextPage)

    # Third, press the goto button
    WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="cPageBtn"]')))
    browser.find_element_by_xpath('//*[@id="cPageBtn"]').click()


def scrap_comments():
    """
    It is a function to scrap User comments, Score, Room types, Dates.
    """
    html = browser.page_source
    soup = BeautifulSoup(html, "lxml")
    scores_total = soup.find_all('span', attrs={"class":"n"})
    # We only want [0], [2], [4], ...
    travel_types = soup.find_all('span', attrs={"class":"type"})
    room_types = soup.find_all('a', attrs={"class":"room J_baseroom_link room_link"})
    travel_dates = soup.find_all('span', attrs={"class":"date"})
    comments = soup.find_all('div', attrs={"class":"J_commentDetail"})
    # Save score in the Score list
    for i in range(2,len(scores_total),2):
        Score.append(scores_total[i].string)
    Travel_Types.append(item.text for item in travel_types)
    Room_Types.append(item.text for item in room_types)
    Travel_Dates.append(item.text for item in travel_dates)
    Comments.append(item.text.replace('\n','') for item in comments)

if __name__ == '__main__':

    # Random choose a user-agent
    user_agent = random.choice(User_Agent_List)
    print('User-Agent: ', user_agent)

    # Browser options setting
    options = Options()
    options.add_argument(user_agent)
    options.add_argument("disable-infobars")

    # Open a Firefox browser
    browser = webdriver.Firefox(options=options)
    browser.get(url)

    #### My ISSUE #####
    browser.find_element_by_xpath('//*[@id="appd_wrap_close"]').click()

    page = 1    
    while page <= DEFINE_PAGE:
        scrap_comments()
        next_page()

    browser.close()

谢谢!

2 个答案:

答案 0 :(得分:1)

好,所以看来必须要切换到某些窗口才能使Selenium单击'//*[@id="appd_wrap_close"]'元素,我尝试了一段时间才找到一个。最终,我认为我偶然发现了阻止您单击该元素的原因。他们安装了测试跟踪软件。这是我发现的方式:首先,我所做的只是显而易见的事情,检查您要单击的'x'元素。我试图找到关于该元素的任何异常信息,过一会儿我发现有一个附加的Event。我在firefox的检查器中单击Event,并看到了以下内容:

'//*[@id="appd_wrap_close"]'

嗯...我希望它能关闭它所在的盒子,但是它具有以下JavaScript:

function() {
  c.setCookie({
    manualclose: "1"
  }, "", 1), u.collapse(), window.__bfi.push(["_tracklog", "pcfloatClose", location.href + "&urlPageId=" + e + "&htmlType=" + d])
}

好吧,这里有u.collapse,我想这是折叠面板所需的全部代码。但是为什么还有其他这些东西呢?有几件事对我来说很奇怪:为什么每次您单击该按钮时都会设置一个cookie?为什么叫**manual**close?然后我靠近一点,看到“点击”后面的文字:_esUnionOnline/R3/float/floating_normal.min.js?20190316:2。嗯因此,他们正在调用javascript文件。那似乎是一个URL。他们为什么要为那个小的“ x”上的mouseclick事件解决所有这些麻烦?

我将鼠标悬停在它上面,并且确实可以看到https://webresource.c-ctrip.com/ResUnionOnline/R3/float/floating_normal.min.js?20190306:2

我导航到该网站并找到一个包含缩小的Javascript的大文件。我将其放置在非缩小符中(我使用了https://unminify.com/)。我在文档顶部看到了

document.getElementById("ab_testing_tracker") && "abTestValue_Value" != h ? 
document.getElementById("ab_testing_tracker").value

ab_testing_tracker .....听起来不太好。因此,我对此进行了搜索,找到了一堆ID为ab_testing_tracker的隐藏输入。在这一点上,我非常确信他们正在检测硒,而不允许您单击。在对常见的测试跟踪方法进行了一些搜索之后,发现除其他外,检查userAgent是很常见的。 Selenium的默认userAgent只是webdriver,因为您可以阅读here,所以我进行了搜索。果然,有20种结果全部以navigator.userAgent的形式出现,有些看起来像

i.test(navigator.userAgent)

然后我注意到您使用的是随机的,合法的userAgent,因此它们必须具有其他检测硒的方法。我确实注意到了此功能

function n() {
    var t, n;
    switch (n = e.ResponseStatus.Errors[0].ErrorCode ? e.ResponseStatus.Errors[0].ErrorCode : "") {
        case "104":
            t = "验证码输入超时";
            break;
        case "105":
            t = "验证码输入错误";
            break;
        case "106":
            t = "手机号码不正确";
            break;
        case "107":
            t = "客户端IP不能为空";
            break;
        case "108":
            t = "短信内容不能为空";
            break;
        case "109":
            t = "同一号码,两分钟内最多发一次";
            break;
        case "110":
            t = "一天内同一手机最多发两次";
            break;
        case "111":
            t = "一天内同一IP最多发五次";
            break;
        default:
            t = "短信发送失败,请重新发送"
    }
    return t
}

在他们的JavaScript中,并借助google translation的帮助,发现最近的几个开关正在检查您是否已访问该网站一定次数。但不幸的是,至少在Firefox中,我无法提出解决此问题的真实方法。

如果您愿意在Chrome中进行测试,则默认情况下(无论出于何种原因)该框都会最小化,因此您不必担心摆脱它。

因此,长话短说,如果您可以在Chrome中进行测试,则只需删除以下行,而不必担心愚蠢的框。测试跟踪器可能仍然会运行,我不知道它是如何工作的,我怀疑他们是自己编写的,因为我找不到使用这些“ ab_test_tracking”节点的任何工具-实际上,在Google上搜索“ ab_test_tracking”的结果很少结果,其中大多数都是这个网站。

让我知道您的选择是什么(出于某种原因需要使用Firefox?),如果您能够在Chrome中运行测试,请告诉我它是否有效!

编辑有关分页按钮 因此,我发现您尝试单击以导航到下一页的按钮也是如此-它具有一个onClick事件,该事件也链接到具有测试跟踪的缩小文件,因此我想这就是您的原因无法单击按钮,硒将永远不会超过第一页。

但是“下一步”按钮没有单击时调用的脚本。您应该能够使用

单击该按钮
browser.find_element_by_xpath('//*[@id="divCtripComment"]/div[4]/div/a[2]')

让我知道这是否适合您。

答案 1 :(得分:0)

由于Peck的指导,我可以完成next_page()函数。但是,弹出窗口是一种浏览器指纹技术,用于通过Web跟踪用户。现在,我们还不知道如何绕过跟踪技术。下面的代码是我完成的next_page()。

def next_page(page):
    """
    It is a function to execute Next Page function
    param: page. # Integer, it depends on what page you want to change to.
    """
    retryNum = 5

    while retryNum >= 0:
        try:
            # page is the page you see right now, what you wanna do is to change to the next page.
            page = page + 1
            # Clear
            browser.find_element_by_id("cPageNum").clear()
            # Send keys
            browser.find_element_by_id("cPageNum").send_keys(page)
            # Click goto button
            browser.find_element_by_id("cPageBtn").click()
            # Sleep for random seconds as waiting for loading
            time.sleep(random.randint(15, 25))
            # Check current page
            currentPage = int(browser.find_element_by_css_selector('a.current').text)

            if currentPage != page:
                retryNum -= 1
                print('Retry!')
                continue
            else:
                break
        except Exception as e:
            assert 'Failed to change to next page'
            return False