最近在学python爬虫,学习到了selenium的使用,看网上有很多使用selenium模拟登录12306网站的文章,于是自己也尝试了一下。期间遇到了一些问题,也参考了很多大佬的文章最终得到了解决,在这里记录下来,作为自己学习之用。

首先我们到12306的登录页面,分析一下登录流程。打开登录页面后,默认是扫码登录,我们点击切换到账号登录,然后输入用户名密码,点击立即登录。这时会出来一个验证窗口,可选滑窗验证和短信验证,默认是滑窗验证。我们拖动滑块,验证通过后如果用户名密码正确,url就会跳转到正常登录页面;如果用户名密码错误会出来错误提示。由于12306网站一直在升级,现在的登录流程跟之前好像不太一样了,我记得之前的验证流程还有选择包含指定物体的图片,目前应该是没有了,处理起来也更简单一些。

分析完后,我们可以用selenium来模拟登录了。先上完整代码,然后再说说遇到的问题。

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver import ActionChains
from selenium.webdriver import ChromeOptions
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import getpassclass Login12306():# Chrome浏览器绕过webdriver检测,可以成功滑窗# 这种方式浏览器没监测到是自动测试工具def __init__(self, url, login_user, login_passwd):option = ChromeOptions()option.add_experimental_option('excludeSwitches', ['enable-automation'])self.driver = webdriver.Chrome(options=option)self.driver.get(url)script = 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined,});'self.driver.execute_script(script) self.driver.maximize_window()self.login_user = login_userself.login_passwd = login_passwdself.init_url = urldef Login(self):# 点击选择账号登录wait = WebDriverWait(self.driver, 60, 0.1)account_login = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.login-hd-account a')))account_login.click()# 输入用户名密码user_input = self.driver.find_element(By.CSS_SELECTOR, 'input#J-userName')user_input.send_keys(self.login_user)time.sleep(1)passwd_input = self.driver.find_element(By.CSS_SELECTOR, 'input#J-password')passwd_input.send_keys(self.login_passwd)time.sleep(1)login_btn = self.driver.find_element_by_css_selector('div.login-btn a#J-login')login_btn.click()# 滑窗验证处理time.sleep(5)span = self.driver.find_element_by_css_selector('#nc_1_n1z')    time.sleep(1)actions = ActionChains(self.driver)time.sleep(2)actions.click_and_hold(span)actions.drag_and_drop_by_offset(span, 300, 0)actions.perform()# 通过url变化与否判断是否登录成功time.sleep(2)print('current_url: ', self.driver.current_url)if self.driver.current_url == self.init_url:# 网页没跳转, 判断是否提示错误信息err_login = self.driver.find_element_by_css_selector('div.login-error')if err_login:if err_login.is_displayed():print('Login Error!')else:try:# 登录成功后,关闭弹出的对话框modal = self.driver.find_element_by_css_selector('div.modal')confirm_btn = self.driver.find_element_by_css_selector('div.modal > div.modal-ft > a')confirm_btn.click()except NoSuchElementException:print('NoSuchElementException')        def main():url = 'https://kyfw.12306.cn/otn/resources/login.html'login_user = input("Input Username: ")login_passwd = getpass.getpass("Input Password: ")global login # 避免chrome浏览器驱动在程序执行完后自动关闭浏览器login = Login12306(url, login_user, login_passwd)login.Login()if __name__ == '__main__':main()

说说遇到的几个问题:

第一个问题:关于网站对selenium等自动化测试工具的反爬处理

一开始我是直接用selenium驱动浏览器打开网页的,此时浏览器打开后会有如下显示:

这说明浏览器已经检测到是自动化工具在控制它。在滑窗验证环节中,出现了如下错误:

拖动滑块后出现了错误提示,开始我以为是selenium做滑窗动作的时候出了问题,但是只要我用selenium打开了浏览器,即使手动拖动滑块还是会出现这个错误提示。后来在网上搜索了一下,发现应该是网站通过js获取了webdriver的属性值。这个值在使用selenium等自动化测试工具时是true,而正常打开网页时是false或者undefined。

检测到这个值是true后,可能就会采取一些反爬措施,比如滑块验证错误。

最终通过这个博客得到了解决。

option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
self.driver = webdriver.Chrome(options=option)
self.driver.get(url)
script = 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined,});'
self.driver.execute_script(script) 

这个代码我其实并没有完全理解,我尝试了一下不配置option选项,只执行修改webdriver值的脚本,浏览器还是会提示是自动化测试工具,但滑窗验证也能通过。此时查看webdriver的值也已经变成了undefined。如果配置了option选项,浏览器就不会出现自动测试工具的提示了。

另外还有一点疑惑:这个js脚本是在get之后修改webdriver的值,这个时候网站应该已经获取了webdriver的值,为什么还能有效呢?我看有些博客也提到了这个问题,而且也提到了其他的解决方法,本人对js不太熟,也没有继续深究了,总之问题得到了解决。

我尝试了用这个方法也是可以的

self.driver = webdriver.Chrome()
self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"""
})
self.driver.get(url)

同时我测试了一下用Firefox,也是同样的问题,最终也是通过执行上述的script脚本得到了解决。

self.driver = webdriver.Firefox()
self.driver.get(url)
script = 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined,});'
self.driver.execute_script(script)
self.driver.maximize_window()

第二个问题:chrome浏览器自动退出问题

当我用chrome浏览器登录成功后,程序退出时,网页也关闭了,如果使用firefox则没有问题。最终参考这篇文章解决了问题。

global login # 避免chrome浏览器驱动在程序执行完后自动关闭浏览器

主要参考文章:

python爬虫实战之旅(12306模拟登录+验证码识别+滑块验证)_KQ的博客-CSDN博客

WebDriver被识别反爬虫解决办法(Chrome正受到自动化测试软件的控制)_成都_杨洋-CSDN博客_webdriver 反爬虫

反反爬虫(0) :还在用 selenium 裸爬吗? 你已经被盯上了!破解WebDriver反爬虫_zzzzls 的博客-CSDN博客_selenium 反爬虫

selenium自动化测试时chrome浏览器为什么会自动关闭? - 知乎

Python+Selenium实现12306模拟登录相关推荐

  1. 12-基于selenium实现12306模拟登录,及京东登录滑动缺口验证模拟登录

    流程分析: 使用selenium打开登录页面 对当前selenium打开的这张页面进行截图 对当前图片的局部区域(验证码图片区域)进行截图 这样验证码图片和模拟登录进行所显示的图片一一对应(如果我们对 ...

  2. python+selenium实现12306自动登录刷票抢票(自己做黄牛?!)

    上一篇写了12306的自动登录破解验证图https://blog.csdn.net/weixin_38283159/article/details/86498159 这篇算是它的后续部分加上了简单的刷 ...

  3. Python+Selenium实现新浪微博自动登录

    Python+Selenium实现新浪微博自动登录 环境说明:win10+eclipse+chrome 备注:需要下载chrome浏览器的驱动(地址: https://sites.google.com ...

  4. python+selenium实现12306抢票

    python+selenium实现12306抢票 一.准备工作 1.要先下载相关的包,selenium.interval.最好使用国内清华源 pip install (which package) - ...

  5. 软件测试案例|Python+Selenium+unittest完成对登录页面的自动化测试

    软件测试案例:Python+Selenium+unittest完成对登录页面的自动化测试 01.实验简介 本实验使用Python语言结合Selenium UI测试工具,利用unittest组织测试用例 ...

  6. 使用selenium解决12306的登录问题

    最近接触了一些selenium模块的相关知识,觉得还挺有意思的,于是决定亲自尝试写一些爬虫程序来强化selenium模块(一定要多尝试.多动手.多总结).本文主要使用python爬虫来模拟登录铁路12 ...

  7. 爬虫|12306模拟登录

    简介: 可以访问蘑菇的BLOG来进行访问 这里是利用了selenium+图片识别验证,来实现12306的模拟登录,中间也参考了好几个项目,实现了这个小demo,中间也遇到了很多的坑,主要难点在于图片识 ...

  8. python + selenium实现12306全自动买票

    整个程序分了三个模块:购票模块(主体).验证码处理模块.余票查询模块 使用方法:三个模块分别保存为三个python文件,名字分别为:book_ticket,captcha,check_ticket. ...

  9. 基于selenium实现12306的登录操作(图形验证码识别)

    说明 12306 会有如下一个图形验证码识别点击,所以必须得先点击正确图片,才能继续进行操作. 基本步骤 selenium打开对应网站,并进行截图 将图片截取出对应验证码所在图片 通过超级鹰识别出要点 ...

最新文章

  1. codeup:问题 D: 最短路径
  2. U盘安装 CentOS 7
  3. Linq(03)基础之Orderby group-by
  4. Python实现FTP服务器和客户端
  5. 一篇彻底搞懂jsp内置对象
  6. OpenGL学习(六)纹理与obj格式模型的读取
  7. 运维工程师到底是做什么的?
  8. Windows的hosts文件在哪里?
  9. FFmpeg指令(./configure 其他)
  10. 微信分享按钮隐藏、显示问题和注意事项
  11. 区块链运作机制_区块链如何运作? 铂 4
  12. Unity任意轴向朝向某目标实现LookAt功能
  13. 2015 UESTC 数据结构专题A题 秋实大哥与小朋友 线段树 区间更新,单点查询,离散化...
  14. 河北工业大学计算机学院考研真题,河北工业大学考研真题汇总
  15. Winsock协议目录
  16. 显示屏服务器出错,电脑显示屏卡顿和出现错误提示怎么办
  17. 音视频基础认知——ISP与DSP
  18. 洛谷 P2862 [USACO06JAN]把牛Corral the Cows
  19. 免费全平台开源商用级OCR: RapidOCR
  20. Unity3D 解决 “SpeedTree materials need to be regenerated.” 导入资源包时出现的错误

热门文章

  1. 聊聊职场或个人事业的生存法则
  2. 寻觅反思,追求卓越——毕业工作所感
  3. 前端图片压缩 pngquanty
  4. Qt 5.12学习笔记--QML性能策略
  5. C#“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke”
  6. 分享实录 | 技术更迭视角下的游戏语音新玩法
  7. 运维平台权限表结构设计
  8. C语言基础——%X(十六进制)的几种不同输出格式
  9. 安装了java但是系统显示没安装_我的世界 已经安装了java,但还是显示没有安装,怎么办...
  10. 嵌入式linux onvif,linux设备上的Onvif 实现3 :gSOAP嵌入式linux下的移植与程序开发