Selenium+requests出现窗口不能跳转的情况

本文介绍使用Selenium和requests进行央视网新闻抓取时遇到的搜索页面跳转问题及解决方案。通过driver.current_window_handle和driver.window_handles判断并切换窗口,实现关键字搜索后的页面自动跳转。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用selenium+requests进行央视网新闻抓取的时候,会出现搜索页面无法跳转的情况。


爬虫设计的思路:

def search()#主要用来打开网页,并输入关键字进行搜索
def get_link_url()#定义抓取链接
def parse_html(link_url):#link_url是个列表,解析每一个链接得到的网页(requests.get())
def get_content(link):#link是个网址的列表,最后得到每一页的内容
def next_page():#定义翻页
def main()

爬虫在新闻搜索页面无法跳转:
可以通过:

driver.currunt_url()#driver=webdriver.Firefox()
In [203]: driver.current_url #还是之前的网址,并没有更新
Out[203]: 'http://www.cctv.com/'

In [204]: driver.current_window_handle#当前位置
Out[204]: '6442450945'

In [205]: driver.window_handles#共有多少个窗口
Out[205]: ['6442450945'] ['6442450949']

多了一个,说明搜索成功了,只是没有跳转.

通常可以通过以下方法解决:

 driver.forward()#表示前进
 driver.switch_to_window()#表示跳转
  • 本文主要采用后者来解决search()的跳转问题。代码如下:
driver = webdriver.Firefox()
wait = WebDriverWait(driver, 10)
  • 第一种:将关键字直接内置,但是对于多个更改关键字不方便.
def search():
    print('正在搜索')
    try:
        driver.get('http://www.cctv.com/')#初始网址
        input = wait.until(
            EC.presence_of_element_located((By.XPATH, '//span//input[@class="input_txt2"]')))
        input.clear()
        input.send_keys("互联网+")#输入关键字
        submit = wait.until(
            EC.element_to_be_clickable((By.XPATH, '//span//input[@type="button"]')))
        submit.click()
        driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
        #跳转到新的窗口
        if driver.current_window_handle==driver.window_handles[-1]:
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
            print("已经自己跳转到新窗口",driver.current_url)  
        else:
            driver.switch_to_window(driver.window_handles[-1])
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
            print("手工跳转",driver.current_url)
        return driver.current_url
    except TimeoutException:
        return search()

其中:

if driver.current_window_handle==driver.window_handles[-1]:
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')#向下滚动
            print("已经自己跳转到新窗口",driver.current_url)  
        else:
            driver.switch_to_window(driver.window_handles[-1])#认为最后一个就是搜索得到的窗口
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
            print("手工跳转",driver.current_url)`
   #  可以执行跳转,但是会出现switch_to_window的弃用警告(***暂时可以忽略***)。
  • 第二种 :将关键字作为搜索参数.
def search(name):#name为关键字
    print('正在搜索')
    try:
        driver.get('http://www.cctv.com/')
        input = wait.until(
            EC.presence_of_element_located((By.XPATH, '//span//input[@class="input_txt2"]')))
        input.clear()
        input.send_keys(name)
        submit = wait.until(
            EC.element_to_be_clickable((By.XPATH, '//span//input[@type="button"]')))
        submit.click()
        driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
        #跳转到新的窗口
        if driver.current_window_handle==driver.window_handles[-1]:
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
            print("已经自己跳转到新窗口",driver.current_url)  
        else:
            driver.switch_to_window(driver.window_handles[-1])
            driver.execute_script('window.scrollTo(0,"document.body.scrollHeight")')
            print("手工跳转",driver.current_url)
        return driver.current_url
    except TimeoutException:
        return search()

  • 所有的都执行完,发现这类不能自动跳转的,driver.close()并不能关闭所有的窗口,这里通过自定义函数实现:
#定义一个关浏览器的函数
def driver_close():
    for i in driver.window_handles:
        driver.switch_to_window(i)
        driver.close() 

欢迎进行爬虫交流

参考
崔庆才;课时1-3的代码

<think>我们正在使用Selenium实现12306抢票自动化。根据引用内容,我们已经掌握了Selenium的基本操作,包括处理验证码、跳转网页、处理内嵌框架等。现在,我们将按照步骤来实现这个功能。主要步骤包括:1.准备工作:安装必要的包和浏览器驱动。2.访问12306网站,登录账户。3.处理登录过程中的验证码(12306的验证码比较复杂,可能需要人工干预或使用第三方验证码识别服务)。4.填写出发地、目的地、日期等信息并查询车票。5.选择车次和座位类型,添加乘客。6.提交订单,确认并支付(支付环节通常需要人工操作,因为涉及银行交互)。由于12306网站结构可能会变化,以下代码可能需要调整。###代码实现步骤####1.准备工作安装必要的包:```bashpipinstallseleniuminterval-ihttps://pypi.tuna.tsinghua.edu.cn/simple```下载对应浏览器的驱动(如Chrome的chromedriver),并确保驱动所在的目录在系统PATH中,或者在代码中指定驱动路径。####2.初始化WebDriver```pythonfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasECimporttime#指定chromedriver路径,如果已经加入环境变量则需要driver=webdriver.Chrome(executable_path='chromedriver路径')driver.maximize_window()#最大化窗口```####3.访问12306登录页面```pythondriver.get("https://kyfw.12306.cn/otn/login/init")```####4.登录由于12306登录需要验证码,这里我们可能需要人工输入验证码,或者尝试使用第三方验证码识别服务(但12306验证码识别难度较大,通常需要人工)。等待用户输入用户名、密码和验证码,然后点击登录按钮。```python#等待用户输入username=driver.find_element(By.ID,"username")password=driver.find_element(By.ID,"password")#假设用户手动输入,我们等待一段时间time.sleep(20)#等待20秒,让用户输入#点击登录按钮driver.find_element(By.ID,"loginSub").click()```####5.跳转到车票预订页面登录成功后,我们跳转到车票预订页面。```python#等待登录成功,然后点击“车票预订”标签WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.LINK_TEXT,"车票预订"))).click()```####6.填写查询条件在车票预订页面,填写出发地、目的地、日期等信息。```python#出发地from_station=driver.find_element(By.ID,"fromStationText")from_station.click()from_station.send_keys("北京")#示例#选择下拉框中的第一个匹配项(实际中需要更精确的选择)WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//ul[@id='ul_list1']/li[1]"))).click()#目的地to_station=driver.find_element(By.ID,"toStationText")to_station.click()to_station.send_keys("上海")WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//ul[@id='ul_list1']/li[1]"))).click()#日期选择,这里选择今天后的第二天(示例)#注意:12306日期输入框是只读的,需要通过js来赋值date_input=driver.find_element(By.ID,"train_date")driver.execute_script("arguments[0].removeAttribute('readonly')",date_input)date_input.clear()date_input.send_keys("2023-12-31")#替换为需要的日期#点击查询按钮driver.find_element(By.ID,"query_ticket").click()```####7.选择车次和座位查询后,在车次列表中选择需要的车次和座位类型。```python#等待查询结果出现WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH,"//tbody[@id='queryLeftTable']/tr")))#选择第一个车次的二等座(根据实际情况调整)#注意:车次列表中的每一行可能有多个车次信息,需要根据具体结构定位#这里假设每一行是一个车次,二等座对应的按钮是第8个(索引从0开始,实际需要查看网页结构)#注意:有些车次可能没有二等座,所以需要判断tr_list=driver.find_elements(By.XPATH,"//tbody[@id='queryLeftTable']/tr[not(@datatran)]")fortrintr_list:#获取车次号,假设在td[0]的位置train_no=tr.find_element(By.XPATH,".//td[1]/div/div").textiftrain_no=='G123':#假设我们要选择G123次#二等座按钮在td[8]的位置,class为ticket-seat,且为可点击的a标签seat_btn=tr.find_element(By.XPATH,".//td[8]/a")ifseat_btn.text=='有'orseat_btn.text.isdigit():#有票seat_btn.click()break```####8.选择乘客并提交在接下来的页面中选择乘客,并提交订单。```python#等待乘客选择页面加载WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.ID,"normalPassenger_0"))).click()#选择第一个乘客#提交订单driver.find_element(By.ID,"submitOrder_id").click()#确认订单WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.ID,"qr_submit_id"))).click()```####9.支付支付环节通常需要人工操作,因为需要输入银行支付密码等。###注意事项1.12306网站经常更新,元素ID或结构可能会变化,需要及时调整。2.验证码处理是一个难点,上述代码中采用人工输入的方式,如果需要自动识别,可能需要接入打码平台(但存在风险)。3.在抢票高峰期,车票可能很快售罄,所以需要断查询(刷新)直到有票。4.需要处理各种异常情况,如网络延迟、元素未加载等。###完整代码示例请注意,以下代码仅为示例,实际运行时需要根据当前网页结构调整。```pythonfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasECimporttime#初始化driver=webdriver.Chrome(executable_path='你的chromedriver路径')driver.maximize_window()try:#登录driver.get("https://kyfw.12306.cn/otn/login/init")time.sleep(20)#等待用户输入用户名、密码和验证码#跳转到车票预订WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.LINK_TEXT,"车票预订"))).click()#填写查询条件#出发地from_station=driver.find_element(By.ID,"fromStationText")from_station.click()from_station.send_keys("北京")WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//ul[@id='ul_list1']/li[1]"))).click()#目的地to_station=driver.find_element(By.ID,"toStationText")to_station.click()to_station.send_keys("上海")WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//ul[@id='ul_list1']/li[1]"))).click()#日期date_input=driver.find_element(By.ID,"train_date")driver.execute_script("arguments[0].removeAttribute('readonly')",date_input)date_input.clear()date_input.send_keys("2023-12-31")#查询driver.find_element(By.ID,"query_ticket").click()#选择车次WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH,"//tbody[@id='queryLeftTable']/tr")))tr_list=driver.find_elements(By.XPATH,"//tbody[@id='queryLeftTable']/tr[not(@datatran)]")fortrintr_list:train_no=tr.find_element(By.XPATH,".//td[1]/div/div").textiftrain_no=='G123':seat_btn=tr.find_element(By.XPATH,".//td[8]/a")ifseat_btn.textin['有','无']orseat_btn.text.isdigit():ifseat_btn.text!='无'andnotseat_btn.text.isdigit()orint(seat_btn.text)>0:seat_btn.click()break#选择乘客WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.ID,"normalPassenger_0"))).click()driver.find_element(By.ID,"submitOrder_id").click()#确认WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.ID,"qr_submit_id"))).click()#等待支付print("请手动完成支付")time.sleep(60)finally:driver.quit()```###相关问题1.如何处理12306的验证码?2.如何提高Selenium自动化脚本的稳定性?3.12306抢票过程中有哪些常见的异常,如何处理?4.如何实现自动监控余票并自动刷新查询?</think>### 使用Selenium实现12306抢票自动化的完整指南 #### 一、准备工作 1. **安装依赖包**: ```bash pip install selenium interval requests pillow -i https://pypi.tuna.tsinghua.edu.cn/simple ``` 2. **浏览器驱动配置**: - 下载与浏览器版本匹配的[chromedriver](https://chromedriver.chromium.org/) - 将驱动放入系统PATH或指定路径 #### 二、核心实现步骤 ```python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time # 初始化浏览器 driver = webdriver.Chrome(executable_path='chromedriver.exe') driver.get("https://kyfw.12306.cn/otn/login/init") # 1. 登录处理 def login(username, password): driver.find_element(By.ID, "username").send_keys(username) driver.find_element(By.ID, "password").send_keys(password) # 验证码处理(需人工识别或接入打码平台) time.sleep(15) # 预留手动操作时间 driver.find_element(By.ID, "loginSub").click() WebDriverWait(driver, 10).until(EC.title_contains("我的12306")) # 2. 车票查询 def search_ticket(from_station, to_station, date): driver.find_element(By.LINK_TEXT, "车票预订").click() # 输入查询条件 driver.find_element(By.ID, "fromStationText").click() driver.find_element(By.ID, "fromStationText").send_keys(from_station) driver.find_element(By.ID, "toStationText").send_keys(to_station) # 日期处理(移除只读属性) date_elem = driver.find_element(By.ID, "train_date") driver.execute_script("arguments[0].removeAttribute('readonly')", date_elem) date_elem.clear() date_elem.send_keys(date) driver.find_element(By.ID, "query_ticket").click() # 3. 车次选择与下单 def select_train(train_no, passenger_name): WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, f"//a[contains(text(),'{train_no}')]")) ) # 选择二等座(根据实际车次调整) driver.find_element(By.XPATH, f"//tr[@datatran='{train_no}']/td[last()-2]/a").click() # 选择乘客 WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, f"//label[contains(text(),'{passenger_name}')]")) ).click() # 提交订单 driver.find_element(By.ID, "submitOrder_id").click() WebDriverWait(driver, 5).until( EC.element_to_be_clickable((By.ID, "qr_submit_id")) ).click() # 主流程 try: login("您的账号", "您的密码") search_ticket("北京", "上海", "2023-12-31") select_train("G123", "张三") print("抢票成功!请及时支付") except Exception as e: print(f"执行失败: {str(e)}") finally: driver.quit() ``` #### 三、关键问题解决方案 1. **验证码处理**: - 方案1:预留15秒手动操作时间(如上代码) - 方案2:接入打码平台(如超级鹰)自动识别 ```python # 示例代码片段 from chaojiying import Chaojiying captcha_elem = driver.find_element(By.ID, "loginCode") captcha_elem.screenshot("captcha.png") # 使用打码平台识别 cjy = Chaojiying('用户名', '密码', '软件ID') result = cjy.post_pic(open('captcha.png','rb').read(), 6113) driver.find_element(By.ID, "randCode").send_keys(result['pic_str']) ``` 2. **余票监控与重试**: ```python import interval from interval import every @every(5.seconds) # 每5秒刷新一次 def monitor_ticket(): driver.refresh() if "有" in driver.find_element(By.XPATH, "//a[@id='ticket_123456']").text: select_train("G123", "张三") ``` 3. **支付处理**: - 跳转支付页面后需人工完成支付 - 可扩展对接支付接口(需谨慎处理安全验证) #### 四、优化建议 1. **稳定性提升**: - 使用`WebDriverWait`显式等待代替`sleep` - 添加异常重试机制(如`retrying`库) ```python from retrying import retry @retry(stop_max_attempt_number=3, wait_fixed=2000) def safe_click(element): element.click() ``` 2. **多线程抢票**: ```python import threading def worker(station): # 每个线程处理同车次 threading.Thread(target=worker, args=("G123",)).start() ``` 3. **日志记录**: ```python import logging logging.basicConfig(filename='ticket.log', level=INFO) ``` #### 五、注意事项 1. 遵守12306使用条款,避免频繁请求(建议间隔≥5秒) 2. 网站结构变更时需及时调整元素定位方式 3. 重要操作前检查登录状态: ```python if "我的12306" not in driver.title: login() ``` > **提示**:完整项目参考[python+selenium实现12306抢票](https://github.com/testerSunshine/12306)[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值