【Python爬虫系列】_016.关于登录和验证码

发布于:2024-09-18 ⋅ 阅读:(53) ⋅ 点赞:(0)

无奋斗不青春

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈
优 质 教 程 推 荐:👉👉 Python爬虫从入门到入狱系列 合集👈👈

分隔线
在这里插入图片描述

关于登录和验证码

关于登录

  • 跟踪登录流程,了解Cookie的生成过程

  • 本次学习以 http://www.woaidu.cc/ 为例进行练习

  • 登录网站 —— 随意找几本小说 —— 在线月度 —— 加入书架 —— 点击右上角的用户名(User) 可以查看到当前账户所有加入书架的书本

  • 要求:获取当前账户下加入书架内所有书本名称

  • 方式一:人工登录,进入书架后,在抓包工具中复制Requests Headers

  • 优点:简单、粗暴

  • 缺点:每次都需要人工登录,手动复制Headers

    import requests
    from lxml import etree
    
    shuj_url = f'http://www.woaidu.cc/bookcase.php'
    session = requests.session()
    # 设置Headers
    session.headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "cookie": "你的cookie信息",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/book_1255314.html",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    # 通过session发送请求
    resp = session.get(shuj_url)
    
    html_code = resp.content.decode("UTF-8")
    
    tree = etree.HTML(html_code)    # type: etree._Element
    names = tree.xpath('//h4[@class="bookname"]/a/text()')
    for name in names:
        print(name)
    
  • 方式二:使用session自动获取cookie

  • 需要看到书架,前提就是需要登录账号

  • 可以先通过代码测试一下没有登录(不携带cookie信息)的时候查看书架是否能看到内容

    import requests
    
    
    url = 'http://www.woaidu.cc/bookcase.php'
    
    my_headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    
    resp = requests.get(url, headers=my_headers)
    print(resp.content.decode('utf-8'))
    
  • 查看结果

    • 在这里插入图片描述
  • 结果发现,当不给cookie信息时,是获取不到书架内容的

  • 测试携带cookie信息

    import requests
    
    
    url = 'http://www.woaidu.cc/bookcase.php'
    
    my_headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "cookie": "你的cookie信息",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    
    resp = requests.get(url, headers=my_headers)
    print(resp.content.decode('utf-8'))
    
  • 查看结果

    • 在这里插入图片描述
  • 添加了cookie信息之后,就能访问到书架了

  • 分析cookie,可以看到当前cookie由以下几个信息组成

    Hm_lvt_1......
    HMACCOUNT
    Hm_lpvt_1......
    username......
    t......
    
  • 其中以 HmHM 开头的cookie是百度排名相关的,可以不用管

    • 在这里插入图片描述
  • 那么跟踪一下 usernamet 的cookie信息

    • 在这里插入图片描述
  • 可以看到 usernamet cookie信息都是通过网址 http://www.woaidu.cc/login.php 响应返回的

  • 清空cookie信息后访问网址,发现是登录页面,说明这两个cookie信息是登录后返回的

    • 在这里插入图片描述
  • 此时,需要再跟踪一下登录时发送请求的情况

  • 打开登录界面,随意输入一个错误的账号密码,点击登录,查看抓包情况

    • 在这里插入图片描述

    • 在这里插入图片描述

  • 抓包可以看到,登录的时候发送了一个post请求,请求参数包含了账号、密码、验证码等

  • 同时,在发送这个post请求的时候,请求头中也是包含了cookie信息

  • 分析改cookie信息,可以看到cookie信息中包含

    Hm_lvt_155d53bb19b3d8127ebcd71ae20d55b1=1725245999; 
    Hm_lpvt_155d53bb19b3d8127ebcd71ae20d55b1=1725245999; 
    HMACCOUNT=832C549F34E314E4; 
    
    c=tq84hVrepXPs......
    
  • 这个cookie信息中 HmHM 开头的cookie是百度排名相关的,可以不用管

  • 那么还有一个 c 的cookie信息,我们尝试不带这个cookie信息是否能登录

    import requests
    
    my_headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "content-length": "153",
        "content-type": "application/x-www-form-urlencoded",
        "cookie": "你的cookie信息",
        "host": "www.woaidu.cc",
        "origin": "http://www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/login.php",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    my_data = {
        "LoginForm[username]": "123123123",
        "LoginForm[password]": "aaaa",
        "LoginForm[captcha]": "4748",
        "action": "login",
        "submit": "登  录"
    }
    
    url = 'http://www.woaidu.cc/login.php'
    
    resp = requests.post(url, headers=my_headers, data=my_data)
    print(resp.content.decode('utf-8'))
    
  • 查看结果

    • 在这里插入图片描述
  • 这里返回的结果,提示的是验证码异常,与之前页面提示的 用户名和密码错误 并不相同

  • 说明这个 c 的cookie信息必须要携带

  • 此时,我们又不能直接复制这个cookie信息,那么我们就需要找到c这个cookie信息是通过哪个请求响应携带回来的

  • 清空抓包数据,重新访问登录页面,全局查找c=,查看这个cookie是通过那个响应数据携带返回的

    • 在这里插入图片描述
  • 再次清空cookie信息和抓包数据,重新访问登录页面,查看刚刚返回c=相关cookie信息的请求

  • 同时,预览这个请求,返回回来的是一个验证码图片

    • 在这里插入图片描述

    • 在这里插入图片描述

  • 可以看到,发送这个请求的时候,请求头中没有再需要携带其他cookie信息,只需要直接访问,就会在返回响应一个验证码图片的时候携带一个cookie信息

  • 此时,通过发送请求,拿到了需要的cookie信息和验证码图片,接下来就是登录了!

  • 问题来了:那拿到这个验证码图片怎么将验证码识别出来添加到请求参数中呢?


关于验证码

  • 验证码识别有两种方式
方式一:免费
  • 使用第三方库:ddddocr
  • 安装
    pip install ddddocr
    
    # 指定安装源
    pip install -i https://mirrors.aliyun.com/pypi/simple ddddocr
    
  • 官方文档
    • https://github.com/sml2h3/ddddocr
  • 使用
    import requests
    import ddddocr
    
    
    url = 'http://www.woaidu.cc/code.php?0.056086518443781985'
    
    my_headers = {
        "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/login.php",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    resp = requests.get(url, headers=my_headers)
    
    image_b = resp.content
    
    # 创建Ddddocr对象, show_ad=False表示不显示广告
    # 使用默认ocr模型
    ddd1 = ddddocr.DdddOcr(show_ad=False)
    result1 = ddd1.classification(image_b)
    print(result1)
    
    # 使用第二ocr模型
    ddd2 = ddddocr.DdddOcr(show_ad=False, beta=True)
    result2 = ddd2.classification(image_b)
    print(result2)
    
方式二:付费
  • 使用第三方api识别

    • 超级鹰:http://www.chaojiying.com/
    • 图鉴:http://ttshitu.com/
    • 两个网站可自行注册、充值
  • 这里以图鉴为例进行测试

  • 打开网址,登录账号 —— 开发文档

    • 在这里插入图片描述

    • 此页面可以先了解一下API如何使用

  • 点击左侧 Python 进入python调用API示例

    • 在这里插入图片描述
  • 复制代码,稍作修改就可以直接用了

    import base64
    import json
    import requests
    
    
    # uname     # 用户名
    # pwd       # 密码
    # img       # 图片地址
    # typeid    # 识别类型
    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"]
        return ""
    
  • 测试API

    import base64
    import json
    import requests
    
    
    url = 'http://www.woaidu.cc/code.php?0.056086518443781985'
    
    my_headers = {
        "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/login.php",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    resp = requests.get(url, headers=my_headers)
    
    with open('code.png', 'wb') as f:
        f.write(resp.content)
    
    
    def base64_api(uname, pwd, img, typeid):
        """
        通过api接口识别图片中的验证码
        :param uname: 用户名
        :param pwd: 密码
        :param img: 图片地址
        :param typeid: 识别类型
        :return:
        """
    
        # base64.b64encode() 对图片进行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"]
        return ""
    
    
    result = base64_api('你的账号', '账号密码', '图片地址', 1001)
    print(result)
    

登录

  • 验证码可以获取到了,那么可以使用代码进行登录了
    import base64
    import json
    
    import requests
    import ddddocr
    
    code_url = 'http://www.woaidu.cc/code.php?0.056086518443781985'
    
    my_headers = {
        "accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
        "accept-encoding": "gzip, deflate",
        "accept-language": "zh-CN,zh;q=0.9",
        "cache-control": "no-cache",
        "connection": "keep-alive",
        "host": "www.woaidu.cc",
        "pragma": "no-cache",
        "referer": "http://www.woaidu.cc/login.php",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    
    # 创建session对象
    session = requests.session()
    
    # 给session对象设置头信息
    session.headers = my_headers
    
    # 使用session发送请求,获取验证码图片
    code_resp = session.get(code_url)
    # 保存验证码图片
    with open('code.jpg', 'wb') as f:
        f.write(code_resp.content)
    
    # 方法一:使用第三方API识别验证码
    def base64_api(uname, pwd, img, typeid):
        """
        通过api接口识别图片中的验证码
        :param uname: 用户名
        :param pwd: 密码
        :param img: 图片地址
        :param typeid: 识别类型
        :return:
        """
    
        # base64.b64encode() 对图片进行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"]
        return ""
    
    # 调用函数,获取验证码
    yzm = base64_api('图鉴网账号', '密码', './code.jpg', 1)
    
    
    # # 方法二:使用ddddocr库识别验证码
    # ocr = ddddocr.DdddOcr(show_ad=False)
    # with open('code.jpg', 'rb') as f:
    #     img_bytes = f.read()
    #
    # yzm = ocr.classification(img_bytes)
    
    
    # 发送post请求,登录,需要携带验证码
    login_url = 'http://www.woaidu.cc/login.php'
    login_data = {
        "LoginForm[username]": "我爱读电子书网账号",
        "LoginForm[password]": "密码",
        "LoginForm[captcha]": yzm,
        "action": "login",
        "submit": "登  录"
    }
    
    # 目的是为了将登录后的cookie信息保存到session对象中
    resp = session.post(login_url, data=login_data)
    
    # 登录成功后,访问个人中心(书架)
    shujia_url = 'http://www.woaidu.cc/bookcase.php'
    shujia_content = session.get(shujia_url)
    print(shujia_content.text)
    

总结

  • 首先查看登录时发送的请求中,请求头中cookie信息
  • 查找cookie信息的来源(通过哪个请求的响应携带回来的)
    • 这个案例中,登录请求的cookie信息是通过验证码请求返回携带的
    • 但有些网站并不是,所以每个网站可能都不同,需要具体跟踪分析
  • 通过session对象发送请求,获取验证码图片,并自动保存cookie信息
  • 识别验证码图片,获取验证码
  • 登录账号、密码、验证码等创建post请求参数
  • 使用保存了cookie信息的session对象向登录页面发送post请求
  • 登录成功之后,session对象会自动保存用户信息到cookie中
  • 最后,使用携带了用户信息cookie的session对象向书架发送get请求