selenium常用API

  • find_element_by_xxx 返回第一个符合条件WebElement元素
  • find_elements_by_xxx 返回符合条件所有元素包含了 WebEelemnt 列表
函数作用
find_element_by_class_name通过class查询元素
find_element_by_id通过ID查询元素
find_element_by_name通过name查询元素
find_element_by_tag_name通过标签名称
find_element_by_css_selectorcss样式选择
find_element_by_link_text通过链接内容查找
find_element_by_partial_link_text通过链接内容包含的内容查找,模糊查询
find_element_by_xpath通过xpath查找数据

获取元素属性和文本内容

1
2
3
4
5
6
7
8
#获取属性
element.get_attribute'属性名”)
#获取文本内容
element.text
# 输入框输入内容
input_element.send_keys'Luenci'
# 元素点击
element.click()

三种等待方式

  • 当控制浏览器时,浏览器正在加载页面同时又去获取数据导致浏览器寻找不到需要操作的元素引发异常。
  • 方式一:强制等待,浪费时间
    • time.sleep(秒数)
  • 方式二:隐性等待,无法控制Ajax请求
    • browser.implicit1y_wait(等待时间)
  • 方式三:显性等待,每个元素都可以自己定义检查条件。手动编写方式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#显性等待-手动编写
t = time.time()
#定义超时时间
timeout = 60
while True
	try
        #超时时间间隔
        time.sleep0.1
        ur1_element = browser.find_element_by_class_name"fav ur1"
		break 
	except
        #超时处理
        if time.time()- t > timeout
        	break 
		pass

系统提供显性等待API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 导入显性等待的API需要的模块
# 1等待对象模块
from selenium.webdriver.support.wait import WebDriverwait
# 2导入等待条件模块
from selenium.webdriver.support import expected_conditions as EC
# 3导入查询元素模块
from selenium.webdriver.common.by import By

# 1.创建等待对象
# 参数一浏览器对象
# 参数二超时时间
# 参数三检查元素时间间隔
wait = WebDriverwaitbrowser5.00.5
# 2.通过等待对象获取元素
# presence_of_element_located 检查元素是否存在,如果存在就返回如果不存在就继续检查
# visibility_of_element_located 检查元素是否可见
linkelement = s wait.untilEC.presence_of_element_located((By.CLASS_NAME"favurl"
link_element.click()

12306爬虫实现

完成代码见:https://github.com/Lucareful/12306_Tickets

  • 实现步骤
    • 1.访问列表页
    • 2.通过时间判定选择点击预订
    • 3.点击账号登录
    • 4.输入用户名和密码(15523750230)
    • 5.截图获取验证码图片
    • 6.发送打码平台获取识别数字
    • 7.定义8个点击坐标
    • 8.模拟点击坐标
    • 9.点击登录
    • 10.点击选择人物
    • 11.点击提交订单
    • 12.点击确认订单
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
# -*- coding: utf-8 -*-
import json
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from PIL import Image
from io import BytesIO
# 判断YDMHTTP模块是否在python环境中(我的是不在,所以加上去)
import sys

sys.path.insert(1, r"YDMHTTP.py")
from YDMHTTP import decode

browser = webdriver.Chrome()
browser.maximize_window()

linktypeid = "dc"
fs = "北京"
ts = "武汉"
date = "2020-01-13"
flag = "N,N,Y"

base_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid={}&fs={},BJP&ts={},WHN&date={}&flag={}'
url = base_url.format(linktypeid, fs, ts, date, flag)

browser.get(url)

wait = WebDriverWait(browser, 10, 0.5)

# 通过时间判定选择预定车次
# 寻找tr标签中的 属性id 已 ’ticket_‘ 开头的数据
tr_list = wait.until(EC.visibility_of_all_elements_located((By.XPATH, '//tr[starts-with(@id, "ticket_")]')))

for tr in tr_list:
    date_string = tr.find_element_by_class_name("start-t").text
    # 判断时间是否在符合你想要的时间范围中
    tr.find_element_by_class_name('no-br').click()
    # print(date_string)
    break

# 点击账号 异步加载需要显性等待
wait.until(EC.visibility_of_element_located((By.LINK_TEXT, "账号登录"))).click()
# browser.find_element_by_link_text("账号登录").click()

# 输入用户名和密码(我将我的用户名和密码保存在了json文件中,若别人使用需要更改)
with open("account.json", "r", encoding="utf-8") as f:
    account = json.load(f)

browser.find_element_by_id("J-userName").send_keys(account["username"])
browser.find_element_by_id("J-password").send_keys(account["password"])

# 获取全屏截图
full_img_data = browser.get_screenshot_as_png()

# 截取验证图片
login_img_element = wait.until((EC.visibility_of_element_located((By.ID, "J-loginImg"))))

# 计算截图位置
# 截取验证码的位置
scale = 2.0
x1 = login_img_element.location["x"]
y1 = login_img_element.location["y"]
x2 = x1 + login_img_element.size["width"] * scale
y2 = y1 + login_img_element.size["height"] * scale

cut_info = (x1, y1, x2, y2)

# 把全屏图片构建成全屏图片操作对象
full_img = Image.open(BytesIO(full_img_data))

# 通过截图信息对象截取图片
cut_img = full_img.crop(cut_info)

# 把图片保存到本地
cut_img.save('demo.png')

# 将验证图片发送到打码平台
result = decode('demo.png', codetype=6701)

# 定义八个点击坐标点
positions = [
    (7.30*25, 140),
    (10.58*25, 140),
    (13.83*25, 140),
    (17.11*25, 140),
    (7.30*25, 250),
    (10.58*25, 250),
    (13.83*25, 250),
    (17.05*25, 250)
]

# 模拟点击坐标
for num in result:
    position = positions[int(num) - 1]
    # 动作对象
    ActionChains(browser).move_to_element_with_offset(login_img_element, position[0]/2, position[1]/2).click().perform()

# 点击登录
browser.find_element_by_id("J-login").click()

# 点击选择乘车人
wait.until(EC.visibility_of_element_located((By.ID, "normalPassenger_0")))

# 点击提交订单
browser.find_element_by_id("submitOrder_id").click()

time.sleep(5)