您好:因为参考的书籍较旧,完全抓不到范例要用selenium去抓资料 URL = "https://tw.hotels.com/"

但目前该网站已经改版,想请问 他会跳出弹掉视窗,要如何销掉目前到这一步 就错了

2.这些元件要如何选择 或直接填入值?

3.下拉选单这要如何选值 或填入?

有试过用copilot问,但不能执行

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

# 初始化WebDriver
driver = webdriver.Chrome() # 请确保chromedriver路径正确
driver.get(\'https://tw.hotels.com/\')

# 输入搜索条件
search_box = driver.find_element(By.ID, \'qf-0q-destination\')
search_box.send_keys(\'台北市\')
search_box.send_keys(Keys.RETURN)

# 选择入住和退房日期
check_in = driver.find_element(By.ID, \'qf-0q-localised-check-in\')
check_in.clear()
check_in.send_keys(\'2024-12-12\')
check_out = driver.find_element(By.ID, \'qf-0q-localised-check-out\')
check_out.clear()
check_out.send_keys(\'2024-12-14\')
check_out.send_keys(Keys.RETURN)

# 等待页面加载
time.sleep(5)

# 抓取酒店信息
hotels = driver.find_elements(By.CLASS_NAME, \'hotel\')
for hotel in hotels:
name = hotel.find_element(By.CLASS_NAME, \'hotel-name\').text
price = hotel.find_element(By.CLASS_NAME, \'price\').text
print(f\'Hotel: {name}, Price: {price}\')

# 关闭浏览器
driver.quit()

谢谢

2 个回答

0

oxiaoyueo

iT邦新手 5 级 ‧ 2024-12-01 04:42:11

你好~
我有稍微测试了一下你的程式码
你使用了ID搜寻,但程式在浏览器找不到"qf-0q-destination"、"qf-0q-localised-check-in"等ID的物件,我自己用浏览器的开发人员工具搜寻也确实如此。
你在文中提到参考书籍较旧,不确定你是不是按照书上key进程式码里,程式才会找不到这些ID。
建议你先使用浏览器内建的开发人员工具(快捷键F12),或是对目标(button、input)右键>检查,来查看物件有什么名称,例如ID、Class、Name等。

找好对应的名称后,可以先测试程式能不能抓到该物件,再继续往下走,避免只有开发人员工具抓到但程式抓不到的状况。
程式抓取方面有分Name、ID、XPath等,我自己是使用XPath,如何使用XPath就请自行搜寻使用方式,这边就不细讲。
以下是範例,在网站选择一个地点:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 初始化WebDriver
driver = webdriver.Edge()
driver.get(\'https://tw.hotels.com/\')

# 先随意选一个选项
target_div = driver.find_element(By.XPATH, "//div[contains(@class, \'uitk-layout-grid-has-auto-rows\')][1]") # 使用XPATH方式找寻物件,选择找到的第一个
target_div.click() # 对目标点击

# 等待选项出现
time.sleep(2)

select_one = driver.find_element(By.XPATH, "//ul/div[1]")
select_one.click()

至于你说的会跳出弹掉视窗,我这边运行上他会自动消失,并没有遇到这个状况。
希望能帮助到你:-)


  • 2

noway

iT邦研究生 1 级 ‧
2024-12-01 20:25:35

您好:谢谢您
我参考您的範例,先单纯填地点
但 地点参数,台北市
他并不会秀在INPUT 上
再按搜寻钮
并没有反映
ElementNotInteractableException: element not interactable
(Session info: chrome=131.0.6778.86)


def search_hotels(searchKey, checkInDate, checkOutDate):
    global driver
    
   # xx=driver.find_elements(By().XPATH ,\'//*[@id="app-layer-base"]/div[1]/div[2]/div[1]/div[1]/div\') # 空白地方
 
    
    
    target_div = driver.find_element(By.XPATH, "//div[contains(@class, \'uitk-layout-grid-has-auto-rows\')][1]") # 使用XPATH方式找寻物件,选择找到的第一个
    target_div.click() # 对目标点击    
    # 等待选项出现
    time.sleep(2)   
    
    #select_one = driver.find_element(By.XPATH, "//ul/div[1]")
    #select_one.click()
 
    
    search_button=driver.find_elements(By().XPATH ,\'//*[@id="search_button"]\') # 查询按钮
    
    
    #driver.find_elements_by_xpath(\'//*[@id="app-layer-base"]/div[1]/div[1]/header/div/section/div/div/div[2]/div[2]/div[2]\')
    #xx=  driver.find_elements_by_xpath(\'//*[@id="app-layer-base"]/div[1]/div[2]/div[1]/div[1]/div/div/div\') #空白地方
    
    # 找出表单的HTML元素
    
    #searchEle =driver.find_elements(By().XPATH ,\'//input[contains(@id,"destination")]\')
    
    
    #searchEle =driver.find_elements(By.XPATH ,\'//input[contains(@class,"uitk-field-input") and  contains(@class,"is-hidden")]\')
    #searchEle =driver.find_elements(By.XPATH ,\'//input[contains(@class,"uitk-field-input") and  contains(@class,"typeahead-custom-text-input")]\' )
    searchEle =driver.find_elements(By.XPATH ,\'//input[contains(@id,"destination_form_field-input")]\')
    
    
    #//*[@id="lodging_search_form"]/div/div/div[1]/div/div/div/div[1]/div
        #EGDSSearchFormLocationField-Location-destination_form_field
  #  print("searchEle",searchEle)
    
    
    #checkInEle = driver.find_elements(By().XPATH ,\'//input[contains(@class,"check-in")]\')
    
   # print("checkInEle", checkInEle)
    
   # checkOutEle = driver.find_elements(By().XPATH ,\'//input[contains(@class,"check-out")]\')
    
    
       #能够找到 3个HTML元素,找到就建立动作链,关闭JS弹出框(有时会有广告) ,然后送出各输入栏位的搜寻条件和日期
    ##if searchEle and checkInEle and checkOutEle:    
    if searchEle :    
        actions = ActionChains(driver)     # 关闭弹出框
        \'\'\'
        actions.send_keys(Keys.TAB)
        actions.send_keys(Keys.TAB)
        actions.send_keys(Keys.TAB)
        actions.send_keys(Keys.TAB)
        \'\'\' 
        actions.send_keys(Keys.ENTER)
        actions.perform() #执行储存动作
        print("searchKey:",searchKey)      
        searchEle[0].send_keys(searchKey)  # 输入搜寻条件
        searchEle[0].send_keys(Keys.TAB)        
        \'\'\'
        checkInEle[0].clear()
        checkInEle[0].send_keys(checkInDate)
        checkOutEle[0].clear()
        checkOutEle[0].send_keys(checkOutDate)
\'\'\'
        #checkOutEle[0].send_keys(Keys.ENTER)  # 送出搜寻        
        search_button.click()
        
        time.sleep(15)
        
        \'\'\'
        menu = driver.find_elements_by_xpath(\'//*[@id="sort-filter-dropdown-sort"][2]\') #已改为Options
        
        if menu:
            actions = ActionChains(driver)    # 选排序选单
            actions.move_to_element(menu[0])
            actions.perform()
            # 找出价格从低至商排序
            price=driver.find_elements_by_xpath(\'//*[@id="sort-submenu-price"]/li[2]/a\')
            if price:
                price[0].click()
                time.sleep(10)
                return True  
         \'\'\'   
    return False

修改

oxiaoyueo

iT邦新手 5 级 ‧
2024-12-03 15:45:58

你好
先给你个建议,贴程式码时,请尽量贴需要的程式码,用不到的程式码请删除,这样方便其他人看你的程式码

分析你的程式码之后,发现你的操作是要直接填入格子中,但hotels网站并不是这样搜寻的,就算成功填入这个格子,搜寻结果并非是你想要的结果。该网站查询地点时会呼叫一个API进行ID查询的动作:API查询高雄结果

你可以看到图中高雄的ID是1808,标记为CITY。如果是图中的高雄万豪酒店,标记为HOTEL,ID为66588735。当使用者点击任一选项后,网站会自动带入ID数值到隐藏输入。
所以你有两种方式可以用,一种是用程式操作的方式,对"想要去哪里?"点击后,追蹤目的地输入框并输入文字,接着追蹤选项并点击,网站的JS会自动带入ID及文字等。
另一种方式是需要接API的方式查询,解析JSON的内容后,因为selenium不能修改隐藏物件的value,因此你必须使用JS修改隐藏数值
以下是小範例:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

# 初始化WebDriver
driver = webdriver.Edge()
driver.get(\'https://tw.hotels.com/\')

# 先随意选一个选项
target_div = driver.find_element(By.XPATH, "//div[contains(@class, \'uitk-layout-grid-has-auto-rows\')][1]")
target_div.click()

# 等待选项出现
time.sleep(2)

select_one = driver.find_element(By.XPATH, "//ul/div[1]")
select_one.click()

# 修改数值区域
\'\'\' 
查询API的程式码...
\'\'\'
location_id = "1808" # 高雄的地区代码
location_input = driver.find_element(By.XPATH, "//input[@name=\'EGDSSearchFormLocationField-RegionId-destination_form_field\']") # 找寻隐藏RegionId 的 input
driver.execute_script("arguments[0].value = arguments[1];", location_input, location_id) # 使用 JS 修改该值
print("新的 value 值:", location_input.get_attribute("value")) # 确认值是否被修改

# 修改入住日期的值
check_in_date = \'2025-01-12\'
check_in = driver.find_element(By.XPATH, "//input[@name=\'EGDSDateRangePicker-StartDate-date_form_field\']")
driver.execute_script("arguments[0].value = arguments[1];", check_in, check_in_date)
print("新的 value 值:", check_in.get_attribute("value"))

# 修改退房日期
check_out_date = \'2025-01-14\'
check_out = driver.find_element(By.XPATH, "//input[@name=\'EGDSDateRangePicker-EndDate-date_form_field\']")
driver.execute_script("arguments[0].value = arguments[1];", check_out, check_out_date)
print("新的 value 值:", check_out.get_attribute("value"))

# 按下搜寻
search_button = driver.find_element(By.ID, "search_button")
search_button.click()

# 等待页面跳转
time.sleep(5)

# 关闭浏览器
driver.quit()

修改

0

itren789

iT邦新手 5 级 ‧ 2024-12-03 11:48:46

您好!根据您提到的问题,您的 Selenium 自动化脚本遇到了一些挑战,这里我会帮您逐一解决,并提供一些具体的解决方案。

1. 处理弹跳视窗
网站上常常会弹出提示框或 cookie 同意视窗,这些视窗会影响您的操作。您可以透过以下方法来关闭这些视窗:

方法一:直接关闭弹出视窗 您可以尝试定位弹出视窗的“关闭”按钮,并进行点击操作。首先要找到该视窗的定位方式,这可以使用浏览器开发者工具来获取该元素的 XPath 或 CSS Selector。

假设弹出视窗有一个 close-button 类名,您可以这样写:

python
Copy code
# 等待弹出视窗并关闭
time.sleep(2)  # 等待几秒钟确保视窗已经显示
close_button = driver.find_element(By.CLASS_NAME, \'close-button\')
close_button.click()

如果视窗的关闭按钮是由其他 ID 或 XPath 定位,请根据实际情况修改。

方法二:使用 WebDriverWait 等待 另外,为了避免 sleep 造成的延迟,您可以使用显式等待来确保元素在可点击时被操作。

python
Copy code
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 等待弹出视窗出现并点击关闭
WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CLASS_NAME, "close-button"))
).click()

2. 填写表单字段
在您的範例中,您需要填写搜寻框、入住日期和退房日期。

搜索框 (qf-0q-destination): 您的代码已经能够正确地填写搜索框,这部分不需要更改。

python
Copy code
search_box = driver.find_element(By.ID, \'qf-0q-destination\')
search_box.send_keys(\'台北市\')
search_box.send_keys(Keys.RETURN)

入住和退房日期 (qf-0q-localised-check-in, qf-0q-localised-check-out): 根据您的描述,您需要进行日期的填入,这部分的代码基本正确,您只需要确保日期格式与网站要求的格式匹配。以下是填入日期的代码:

python
Copy code
check_in = driver.find_element(By.ID, \'qf-0q-localised-check-in\')
check_in.clear()
check_in.send_keys(\'2024-12-12\')

check_out = driver.find_element(By.ID, \'qf-0q-localised-check-out\')
check_out.clear()
check_out.send_keys(\'2024-12-14\')
check_out.send_keys(Keys.RETURN)

如果填写日期仍然不成功,您可以检查日期栏位是否会触发日曆选择器,并通过直接选择日期来填写。

3. 选择下拉选单中的选项
如果您需要选择下拉选单中的项目,可以使用 Select 类来操作。

假设您的下拉选单是基于 ID 或 name 属性识别,您可以这样操作:

python
Copy code
from selenium.webdriver.support.ui import Select

# 假设有一个下拉选单 `room-selection`
select_element = driver.find_element(By.ID, \'room-selection\')
select = Select(select_element)

# 选择一个选项,可以通过索引、选项文字或值来选择
select.select_by_visible_text(\'2 位成人\')
# 或者
select.select_by_value(\'2\')
# 或者
select.select_by_index(1)  # 根据选项的顺序选择

4. 等待网页加载
在进行交互之前,最好等到网页完全加载。使用显式等待可以帮助您避免因为网页尚未加载完成而造成的错误。

python
Copy code
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 等待搜索结果加载
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CLASS_NAME, \'hotel\'))
)

5. 抓取资料
当网页加载完成后,您可以继续抓取酒店信息。假设您希望抓取酒店名称和价格:

python
Copy code
hotels = driver.find_elements(By.CLASS_NAME, \'hotel\')
for hotel in hotels:
    try:
        name = hotel.find_element(By.CLASS_NAME, \'hotel-name\').text
        price = hotel.find_element(By.CLASS_NAME, \'price\').text
        print(f\'Hotel: {name}, Price: {price}\')
    except Exception as e:
        print("Error:", e)

完整範例
综合上述,以下是完整的範例代码:

python
Copy code
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
import time

# 初始化WebDriver
driver = webdriver.Chrome()  # 请确保chromedriver路径正确
driver.get(\'https://tw.hotels.com/\')

# 等待弹出视窗并关闭
WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CLASS_NAME, \'close-button\'))
).click()

# 输入搜索条件
search_box = driver.find_element(By.ID, \'qf-0q-destination\')
search_box.send_keys(\'台北市\')
search_box.send_keys(Keys.RETURN)

# 等待网页加载完成
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, \'qf-0q-localised-check-in\'))
)

# 选择入住和退房日期
check_in = driver.find_element(By.ID, \'qf-0q-localised-check-in\')
check_in.clear()
check_in.send_keys(\'2024-12-12\')

check_out = driver.find_element(By.ID, \'qf-0q-localised-check-out\')
check_out.clear()
check_out.send_keys(\'2024-12-14\')
check_out.send_keys(Keys.RETURN)

# 等待页面加载酒店信息
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CLASS_NAME, \'hotel\'))
)

# 抓取酒店信息
hotels = driver.find_elements(By.CLASS_NAME, \'hotel\')
for hotel in hotels:
    try:
        name = hotel.find_element(By.CLASS_NAME, \'hotel-name\').text
        price = hotel.find_element(By.CLASS_NAME, \'price\').text
        print(f\'Hotel: {name}, Price: {price}\')
    except Exception as e:
        print("Error:", e)

# 关闭浏览器
driver.quit()

这样您应该可以成功处理弹出视窗、填写表单栏位和选择下拉选单。希望这些建议能帮助您顺利完成自动化任务!

更多推荐阅读:
https://momoproxy.com/blog/Python?query=category