• 爬虫的三种数据解析方式和验证码的处理


    1,正则解析:就是通过正则匹配定位到要获取数据的标签,获取响应的数据

    • 直接上代码(以爬取糗事百科为例)
    import requests
    import re
    import os
    if __name__ == '__main__':
        # 访问请求的url
        url = "https://www.qiushibaike.com/pic/page/%s/"
        # 定制请求头
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
        }
        # 指定其实和结束页码
        page_start = input("请输入起始页码:")
        page_end = input("请输入结束页码:")
        # 创建文件夹
        if not os.path.exists("images"):
            os.mkdir("images")
        # 循环解析且下载指定页码中的图片数据
        for page in range(int(page_start), int(page_end)+1):
            print("第%s页图片正在下载" % page)
            new_url = format(url % page)
            response = requests.get(url=new_url, headers=headers)
    
            # 解析response中的图片链接
            e = '<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>'
            pa = re.compile(e, re.S)
            image_urls = pa.findall(response.text)
            # 循环下载该页码下的多有url图片数据
            for image_url in image_urls:
                image_url = "https:" + image_url
                image_name = image_url.split("/")[-1]
                image_path = "images/" + image_name
                image_data = requests.get(url=image_url, headers=headers).content
                # 存储到本地
                with open(image_path, "wb") as fp:
                    fp.write(image_data)

    2,xpath的表达式:是一种用来定位标签的层级关系的一中表达式

    • xpath表达式的要点:
    # 属性定位:
        # 找到class属性值为xuexue的div标签
        //div[@class='xuexue']  # //表示多层目录下
    # 层级&索引定位:
        
        # 找到class属性值为xue的div的直系子标签ul下的第二个子标签li下的直系a标签
        //div[@class="xue"]/ul/li[2]/a  # xpath表达式支持索引,但索引是从1开始的
    # 逻辑运算:
        # 找到href属性值为空且class属性值为du的a标签
        //a[@href="" and @class="du"]  # xpath 表达式支持偶家运算
    #模糊胡匹配:
        //div[contains(@class, "ng")]
        //div[starts-with(@class, "ta")]
    #取文本:
        #表示获取某个标签下的文本内容
        #//表示获取某个标签下文本内容和所有子标签下的文本内容
        //div[@class="xuexue"]/p[1]/text()
        //div[@class="xuexue"]//text()
    # 取属性:
        // div[@class="xuexue"]//li[2]/a/@href
    • 代码中xpath表达式进行数据解析:
      1. 下载:pip install lxml
      2. 导包: from lxml import etree
      3. 将html文档或xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
        1. 本地文件: tree = etree.parse(文件名)    tree.xpath("xpath表达式")
        2. 网络数据:tree = etree.HTML(网页内容字符串)   tree.xpath("xpath表达式")
    • 安装xpath插件在浏览器中对xpath表达式进行验证:可以在插件中直接执行xpath表达式
      • 将xpath插件拖动到谷歌浏览器拓展程序(更多工具中),真能装成功!!!
      • 启动和关闭插件:ctrl + shift + x
    • 下载简单中的图片数据
    import requests
    from lxml import etree
    import base64
    from urllib import request
    # 指定要访问的url
    url = "http://jandan.net/ooxx"
    # 指定响应头
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
    }
    page_text = requests.get(url=url, headers=headers).text
    tree = etree.HTML(page_text)
    imgCode_list = tree.xpath("//span[@class='img-hash']/text()")
    imgUrl_list = []
    for url in imgCode_list:
        img_url = "http:" + base64.b64decode(url).decode()
        imgUrl_list.append(img_url)
    
    for url in imgUrl_list:
        filePath = url.split("/")[-1]
        request.urlretrieve(url=url, filename=filePath)
        print(filePath + "下载成功!")
    # 查看页面源码:发现所有图片的src值都是一样的。
    #简单观察会发现每张图片加载都是通过jandan_load_img(this)这个js函数实现的。
    #在该函数后面还有一个class值为img-hash的标签,里面存储的是一组hash值,该值就是加密后的img地址
    #加密就是通过js函数实现的,所以分析js函数,获知加密方式,然后进行解密。
    #通过抓包工具抓取起始url的数据包,在数据包中全局搜索js函数名(jandan_load_img),然后分析该函数实现加密的方式。
    #在该js函数中发现有一个方法调用,该方法就是加密方式,对该方法进行搜索
    #搜索到的方法中会发现base64和md5等字样,md5是不可逆的所以优先考虑使用base64解密
    #print(page_text)
    
    
    #在抓包工具的数据包响应对象对应的页面中进行xpath的编写,而不是在浏览器页面中。
    #获取了加密的图片url数据

    3,BeautifulSoup解析

    • 环境的安装
      1. 需要将pip原设置为国内源,阿里源,豆瓣源,网易源等
      2. windows
        1. 打开文件资源管理器(文佳佳地址栏中)
        2. 地址栏上面输入 %appdata%
        3. 在这里建一个文件夹 pip
        4. 在pip文件夹里新建一个文件叫做pip.ini,内容如下写即可
          • [global]
          • timeout = 6000
          • index-url = https://mirrors.aliyun.com/pypi/simple/
          • trusted-host = mirrors.aliyun.com
      3. linux中:
        1. cd ~
        2. mkdir ~/.pip
        3. vi ~/.pip/pip.conf
        4. 编辑内容,和windows一样
      4. 需要安装:pip install bs4
        • bs4在使用时候需要一个第三方的库, 把这个库也安装一下
        • pip install lxml
    • 基础使用
      1. 导包: from bs4 import BeautifulSoup
      2. 使用方式:可以将html文档,转化为BeautifulSoup对象,然后通过对象的方法 或者属性去查找指定节点的内容
        1.  转化本地文件: soup = BeautifulSoup(open("本地文件"), "lxml")
        2. 转化网络文件: soup = BeautifulSoup("字符串类型或者字节类型", "lxml")
        3. 打印soup对象显示内容为htnl文件中的内容
    • BeautifulSoup知识点:
      1. 根据标签名查找:
        • soup.a   只能查找第一符合要求的标签
      2. 获取属性:
        • soup.a.attrs    获取所有属性和属性值,返回一个字典
        • soup.a.attrs["href"]    获取href属性
        • soup.a["href"]    也可以简写成这种形式
      3. 获取内容
        • soup.a.string
        • soup.a.text
        • soup.a.get_text()
        • 注意,如果标签还有标签,那么string获取到的结果为None,而其他两个,可以获取文本内容
      4. find:找到第一个 符合要求的标签
        • soup.find("a")   找到第一个符合要求的
        • soup.find("a", title="xuexue")
        • soup.find("a", alt="xuexue")
        • soup.find("a", class="xuexue")
        • soup.find("a", id="xuexue")
      5. find_all:找到所有符合 要求的标签
        • soup.find_all("a")
        • soup.find_all(["a","b"])   # 找到所有的a标签和b标签
        • soup.find_all("a", limit=2)  # 限制前两个
      6. 根据选择器选择指定的内容
        • select:soup.select("#feng")
        • 常见的选择器:标准选择器(a),类选择器(.),id选择器(#),层级选择器
          • 层级选择器:
            • div.xuexue #xiaoxue.haha .hehe   下面好多级
            • div>p>a>.xuexue   只能是下面一级
          • 注意:select选择器返回的 永远是列表,需要通过下标提取指定的对象

    相关的代码如下:

    import requests
    from bs4 import BeautifulSoup
    # 指定响应头
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
    }
    
    
    # 定义解析内容的函数
    def parse_content(url):
        # 获取标题正文页数据
        page_text = requests.get(url=url, headers=headers).text
        # 实例化一个BeautifulSoup对象
        soup = BeautifulSoup(page_text, "lxml")
        # 解析获得标签
        element = soup.find("div", class_="chapter_content")
        content = element.text  # 获取标签中的数据值
        return content
    
    if __name__ == '__main__':
        url = "http://www.shicimingju.com/book/sanguoyanyi.html"
        # 发送请求后的响应体
        response = requests.get(url=url, headers=headers)
        page_text = response.text
        print(page_text)
    
        # 创建soup对象
        soup = BeautifulSoup(page_text, "lxml")
        # 解析数据
        a_else = soup.select(".book-mulu>ul>li>a")
        print(a_else)
        cap = 1
        for ele in a_else:
            print("开始下载di%s章节" % cap)
            cap += 1
            title = ele.string
            content_url = "http://www.shicimingju.com" + ele["href"]
            content = parse_content(content_url)
            print(content)
            content = content.replace("xa0", "")
    
            # 持久化存储
            with open("./mengsanguo.txt", "w") as fp:
                fp.write(title + ":" + content + "
    
    
    
    
    ")
                print("结束下载第%s章节" % cap)

    4,验证码的处理

    • 相关门户网站进行登录的时候,如果用户连续登录的次数超过3次或者5次的时候,就会在登录页面中生成验证码,通过验证码达到分流和反爬的效果
    • 云打码处理平台是一个很好的处理验证码的平台

    云打码平台处理验证码实现流程:

    1. 对携带验证码的页面数据进行爬取
    2. 可以将页面数据中验证码进行解析,验证码图片下载到本地
    3. 可以将 验证码图片提交给第三方平台进行识别,返回验证码图片上的数据值
      • 云打码平台:
        1. 在官网中注册(普通用户和开发者用户)
        2. 登录开发者用户:
          1. 实例代码的下载
          2. 创建一个软件
        3. 使用实例代码中的源码文件中的代码进行修改,让其识别验证码图片中的数据值
    4. 代码展示:
    # 该函数调用了打码平台的相关的接口对指定的验证码图片进行识别,返回图片上的数据值
    def getCode(codeImg):
        # 云打码普通用户的用户名
        username = "xueren"
        # 云打码平台普通用户的密码
        password = "xueren123"
        # 软件ID,开发者分成必要参数,登录开发者后台[我的软件]获得!
        # 软件密钥,开发者分成必要参数 ,登录开发者后台[我的软件]获得!
        appkey = "4997f67b0128c77cda6db5259f5f76a9"
        # 验证码图片文件
        filename = codeImg
        # 验证码类型, 列如:1004表示4位字母数字,不同类型收费不同,请准确 填写,否则影响别率
    查询所有验证码类型:http://www.yundama.com/price.html
        codetype = 3000
        # 超市时间,秒
        timeout = 20
        # 检查
        if (username == "username"):
            print("请设置好相关参数再测试")
        else:
            # 初始化
            yundama = YDMHttp(username, password, appid, appkey)
            # 登录云打码
            uid = yundama.login()
            print("uid: %s" % uid)
            # 查询余额
            balance = yundama.balance()
            print("balance:"% balance)
            # 开始识别,图片路径, 验证码类型ID,超时时间(秒), 识别结果
            cid, result = yundama.decode(filename, codetype, timeout)
            print("cod: %s, result: %s" % (cid, result))
            return  result

    人人网验证码的爬取及处理:

    def get_code_text(codeType, imgPath):
        # 用户名:普通用户
        username = "xueren"
        # 密码
        password = "xueren123"
        # 软件ID, 开发者分成必要参数.登录开发者后台[我的软件]获得!
        appid = 6609
        # 软件密钥,开发者分成必要参数,登录开发者后台[我的软件]获得!
        appkey = "4997f67b0128c77cda6db5259f5f76a9"
        # 图片文件
        filename = imgPath
        # 验证码类型, # 列:1004表示4位字母数字,不同类型收费不同.请准确填写,否则影响识别率.
        # 在此查询所有类型 http://www.yundama.com/price.html
        codetype = codeType
        # 超时时间,秒
        timeout = 10
        # 检查
        if(username == "username"):
            print("请设置好相关参数在测试")
        else:
            yundama = YDMHttp(username, password, appid, appkey)
            # 登录云打码
            uid = yundama.login();
            print("uid:%s" % uid)
            
            # 查询余额
            balance = yundama.balance();
            print("balance %s" % balance)
            # 开始识别,图片路径,验证码类型ID, 超时时间(秒), 识别结果
            cid, result = yundama.decode(filename, codeType, timeout);
            # print("cid: %s, result: %s" % (cid, result))
            return result
    import requests
    from lxml import etree
    from urllib import request
    # 获取一个session对象
    session = requests.Session()
    # session对象和requests作用几乎一样,都可以进行请求的发送,并且请求发送的方式也是一样的
    # session进行请求的发送,如果会产生cookie的话 ,则cookie会自动被存储到session中
    # 获取验证码图片
    # 找到请求的url
    url = "http://www.renren.com/"
    # 找到请求的请求头UA
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
    }
    # 向人人网发送请求,拿到验证码
    page_text = requests.get(url=url, headers=headers).text
    # 将验证码图片解析出来进行持久化存储
    tree = etree.HTML(page_text)
    # 拿到验证码的url
    code_img_src = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
    code = None
    if code_img_src:
        # 保存验证码图片
        request.urlretrieve(url=code_img_src, filename="./code.jpg")
        # 调用damayun破解验证码
        code = get_code_text(2004, "./code.jpg")
        print(code)
    # 模拟登陆
    login_url = "http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201903209693"
    data = {
        'email': "18731229751",
        "icode": code,
        "origURL": "http://www.renren.com/home",
        "domain": "renren.com",
        "key_id":"1",
        "captcha_type": "web_login",
        "password": "2ffe7682a8e5f246b91115f02ed84bec462e9e81cb1d53c26159c422b2bf4b23",
        "rkey": "8903172b11d2f2476d3db75417116a1c",
        "f": "https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D52HnJhxy_aSfPbj2R5LMlG4a6294qGfXen5puJr--HG%26wd%3D%26eqid%3D9e26635d000114c1000000035c35e61e",
    }
    # 进行登录, 当登录成功之后,可以获取cookie
    # cookie会被保存到sessio中
    response = session.post(url=login_url, headers=headers, data=data)
    # 对登录成功后对应的当前用户的个人详情页面进行请求发送
    detail_url = "http://www.renren.com/969397800/profile"
    # 该次请求使用的是session对象,该请求已经携带了cookie
    page_text = session.get(url=detail_url, headers=headers).text
    
    # 保存到本地
    with open("./renren.html", "w", encoding="utf-8") as fp:
        fp.write(page_text)
        print("ok")
  • 相关阅读:
    腾讯TBS加载网页无法自适应记录
    filter过滤器实现验证跳转_返回验证结果
    Oracle不连续的值,如何实现查找上一条、下一条
    springmvc.xml 中 <url-pattern></url-pattern>节点详解
    spring拦截器-过滤器的区别
    (转)spring中的拦截器(HandlerInterceptor+MethodInterceptor)
    @Value("${xxxx}")注解的配置及使用
    mybatis BindingException: Invalid bound statement (not found)
    spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)
    Spring事务管理详解_基本原理_事务管理方式
  • 原文地址:https://www.cnblogs.com/ljc-0923/p/10331779.html
Copyright © 2020-2023  润新知