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

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 + "\n\n\n\n\n") 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")

猜你喜欢

转载自www.cnblogs.com/ljc-0923/p/10331779.html