selenium小进阶+案例

selenium小进阶+案例

关于验证码

验证码处理:

1. 直接把浏览器里面的cookie拿出来直接用. 
2. 手动编写验证码识别的功能(深度学习)
3. 第三方打码平台(收费), 超级鹰, 图鉴

 

图鉴-好东西http://www.ttshitu.com/

这个东西. 既便宜. 有好用. 比超级鹰爽.

官方示例:

import base64
import json
import requests
# 一、图片文字类型(默认 3 数英混合):
# 1 : 纯数字
# 1001:纯数字2
# 2 : 纯英文
# 1002:纯英文2
# 3 : 数英混合
# 1003:数英混合2
#  4 : 闪动GIF
# 7 : 无感学习(独家)
# 11 : 计算题
# 1005:  快速计算题
# 16 : 汉字
# 32 : 通用文字识别(证件、单据)
# 66:  问答题
# 49 :recaptcha图片识别 参考 https://shimo.im/docs/RPGcTpxdVgkkdQdY
# 二、图片旋转角度类型:
# 29 :  旋转类型
#
# 三、图片坐标点选类型:
# 19 :  1个坐标
# 20 :  3个坐标
# 21 :  3 ~ 5个坐标
# 22 :  5 ~ 8个坐标
# 27 :  1 ~ 4个坐标
# 48 : 轨迹类型
#
# 四、缺口识别
# 18 : 缺口识别(需要2张图 一张目标图一张缺口图)
# 33 : 单缺口识别(返回X轴坐标 只需要1张图)
# 五、拼图识别
# 53:拼图识别
def base64_api(uname, pwd, img, typeid):
    with open(img, 'rb') as f:
        base64_data = base64.b64encode(f.read())
        b64 = base64_data.decode()
    data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]

if __name__ == "__main__":
    img_path = "xxxx.jpg"
    result = base64_api(uname='q6035945', pwd='q6035945', img=img_path, typeid=3)
    print(result)

非常的简单.

老规矩. 我要用图鉴干图鉴, selenium那个上节课讲过了. 这节课我们讲requests

# 用requests来完成登录过程
# 一般情况下. 在使用验证码的时候. 要保持住会话. 否则容易引起,验证码识别不成功的现象
import time

import requests
import base64
import json


def base64_api(uname, pwd, img, typeid):
    data = {"username": uname, "password": pwd, "typeid": typeid, "image": img}  # 直接把img搞进来
    result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]


session = requests.session()
# 1.设置好头信息
session.headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36"
}

# 2. 加载一个最原始的cookie(可能需要可能不需要. 好习惯)
session.get("http://www.ttshitu.com/login.html?spm=null")

# 3. 发送请求. 拿到验证码
verify_url = "http://admin.ttshitu.com/captcha_v2?_=1650111626736"  # url屁股上总能看见_ t n  => 时间戳
resp = session.get(verify_url)
img = resp.json()['img']  # 拿图片
imgId = resp.json()['imgId']  # 图片ID

# 4.识别验证码
verify_code = base64_api("q6035945", "q6035945", img, 1)

username = "q6035945"
password = "q6035945"

# 准备登录
login_url = "http://admin.ttshitu.com/common/api/login/user"
data = {
    "captcha": verify_code,
    "developerFlag": False,
    "imgId": imgId,
    "needCheck": True,
    "password": password,
    "userName": username,
}
# 我们在浏览器中发现了一种全新的参数逻辑
# Request Payload
# 第一, 发送出去的是json
# 第二, 请求一定是post
# 第三, 它的请求头里一定有content-type:application/json;
# resp = session.post(login_url, data=json.dumps(data), headers={"Content-Type": "application/json; charset=UTF-8"})
resp = session.post(login_url, json=data)  # 如果给了json参数. 自动的帮你转化和处理. 以及请求头的处理
print(resp.text)

 

关于等待

在selenium中有三种等待方案

  1. time.sleep()

    这个没啥说的. 就是干等. 不论元素是否加载出来. 都要等

  2. web.implicitly_wait(10)

    这个比上面那个人性化很多. 如果元素加载出来了. 就继续. 如果没加载出来. 此时会等待一段时间.

    注意, 此设置是全局设置. 一次设置后. 后面的加载过程都按照这个来. (爬虫用的会多一些)

  3. WebDriverWait

    这个比较狠. 单独等一个xxxx元素. 如果出现了. 就过, 如果不出现. 超时后, 直接报错.

    ele = WebDriverWait(web, 10, 0.5).until(
            EC.presence_of_element_located((By.XPATH, "/html/body/div[5]/div[2]/div[1]/div/div"))
        )

 

Selenium搞定bilibili登录

我们用Selenium来模拟一下bilibili的登录过程(现在是点选登陆, 如果是滑块,干不过去。).

from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time
import base64
import requests
import json

def base64_api(uname, pwd, img, typeid):
    # 官方的案例. 是把一张图片. 处理成了base64
    with open(img, 'rb') as f:
        base64_data = base64.b64encode(f.read())
        b64 = base64_data.decode()

    data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]

web = Chrome()
web.implicitly_wait(10)  # 软等待
web.get("http://www.bilibili.com")

web.find_element(By.XPATH, '//*[@class="header-login-entry"]/span').click()

web.find_element(By.XPATH, '//*[@class="bili-mini-account"]/input').send_keys("12345789")
web.find_element(By.XPATH, '//*[@class="bili-mini-password"]/div[1]/input').send_keys("123456")

time.sleep(3)  # 这里只能硬等待
web.find_element(By.XPATH, '//*[@class="universal-btn login-btn"]').click()

tu = web.find_element(By.XPATH, '//*[@class="geetest_widget geetest_medium_fontsize"]')
tu.screenshot("tu.png")  # 把图片存储在文件中
# tu.screenshot_as_png()  # 直接拿到字节
result = base64_api("q6035945", "q6035945", "tu.png", 27)
print(result)

# 180,71|57,89|78,151
# 180,71
# 57,89
# 78,151
rs = result.split("|")
for r in rs:  # 180,71
    x, y = r.split(",")
    x = int(x)
    y = int(y)  # 转化成数字
    # 找到截图的那个位置的左上角, 横向移动xxx, 纵向移动xxx, 点击
    # 事件链, 动作链  一系列的操作
    ActionChains(web).move_to_element_with_offset(tu, xoffset=x, yoffset=y).click().perform()
    time.sleep(1)
time.sleep(1)
web.find_element(By.XPATH, "//*[@class='geetest_commit_tip']").click()

 

Selenium可以获取到Elements的结构代码

import time

from selenium.webdriver import Chrome
from selenium.webdriver.common.by import By
from lxml import etree

web = Chrome()
web.implicitly_wait(10)

def get_page_source(url):
    web.get(url)
    time.sleep(3)
    return web.page_source  # selenium中的page_source 是elements

if __name__ == '__main__':
    url = "https://search.bilibili.com/all?keyword=%E5%87%A4%E5%87%B0%E8%8A%B1%E5%BC%80%E7%9A%84%E8%B7%AF%E5%8F%A3&from_source=webtop_search&spm_id_from=333.1007&page=3&o=72"
    page_source = get_page_source(url)
    tree = etree.HTML(page_source)
    txt = tree.xpath("//*[@class='video-list row']//text()")
    print(txt)

 

利用selenium登录12306

12306网站已经改版. 没有了以前烦人的验证码. 此时登录非常顺滑.

在最后一步, 进入滑块环节, 这里其实看似容易, 操作起来就恶心了. 因为这里才是本节真正要讲的. 12306会在这里进行浏览器验证, 验证你是否是通过自动化工具启动的浏览器. 而且, 这个问题非常恶心, 常规的浏览器检测处理方案都是没用的.

注意:如果是用自动化工具打开的登陆界面,当打开F12,在 Console 中输入 window.navigator.webdriver 返回的是 True 。

注意, 此时我们要了解一下这个插件的工作机制. 它是在整个页面加载的时候就开始对浏览器参数进行读取. 所以我们常规的对Chrome设置是无效的. 此时, 需要添加以下一段代码来规避检测.

# 亲测, 88版本以后可以用.
option = Options()
# option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_argument('--disable-blink-features=AutomationControlled')
web = Chrome(options=option)

# 亲测, 88版本之前可以用.
# web = Chrome()
#
# web.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
#   "source": """
#   navigator.webdriver = undefined
#     Object.defineProperty(navigator, 'webdriver', {
#       get: () => undefined
#     })
#   """
# })

 

最后给出完整代码

from selenium.webdriver import Chrome
from selenium.webdriver.support.ui import WebDriverWait  # 等待
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options

opt = Options()
# 处理 检测webdriver
opt.add_argument('--disable-blink-features=AutomationControlled')

web = Chrome(options=opt)

web.get("https://kyfw.12306.cn/otn/resources/login.html")
web.implicitly_wait(10)
web.find_element(By.XPATH, '//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[1]/a').click()

web.find_element(By.XPATH, '//*[@id="J-userName"]').send_keys("hehehe@126.com")
web.find_element(By.XPATH, '//*[@id="J-password"]').send_keys("111111")

web.find_element(By.XPATH, '//*[@id="J-login"]').click()

# 滑动
# 找到滑块
btn = web.find_element(By.XPATH, '//*[@id="nc_1_n1z"]')
ActionChains(web).click_and_hold(btn).move_by_offset(0, 300).perform()

 

总结, selenium的使用方案一般是:

  1. 涉及登录. 验证码不想搞.

    可以考虑用selenium完成登录. 然后提取cookie. 最后用requests发送真正的请求.

  2. 涉及频繁的校验验证(例如boss).

    直接用selenium提取页面源代码. 叫给lxml处理.

     

cookie的小问题

获取cookie

我们用17k.com来做实验.

from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
import json

web = Chrome()
web.get('https://www.17k.com/')
web.implicitly_wait(10)

# 登录
web.find_element(By.XPATH, '//*[@id="header_login_user"]/a[1]').click()
​
# 切换iframe
iframe = web.find_element(By.XPATH, '//div[@class="QUI_POP_CONT"]/iframe')
web.switch_to.frame(iframe)

web.find_element(By.XPATH, '/html/body/form/dl/dd[2]/input').send_keys("18614075987")
web.find_element(By.XPATH, '/html/body/form/dl/dd[3]/input').send_keys("q6035945")

web.find_element(By.XPATH, '/html/body/form/dl/dd[5]/input').click()

time.sleep(3)

cookies = web.get_cookies()

# 存文件里
with open("cookies.txt", mode="w", encoding='utf-8') as f:
    f.write(json.dumps(cookies))

# 组装cookie字典, 直接给requests用
dic = {}
for cook in cookies:
    dic[cook['name']] = cook['value']

# 衔接. 把cookie直接怼进去
import requests

url = "https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919"
resp = requests.get(url, cookies=dic)
print(resp.text)

 

设置cookie

web.get('https://www.17k.com/')  # 打开
with open("cookies.txt", mode="r", encoding='utf-8') as f:
    cookies = json.loads(f.read())

    for cook in cookies:
        web.add_cookie(cook)

web.get('https://www.17k.com/')  # 打开

 

posted @ 2022-05-24 10:00  屠魔的少年  阅读(10)  评论(0)    收藏  举报