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表达式进行数据解析:
- 下载:pip install lxml
- 导包: from lxml import etree
- 将html文档或xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
- 本地文件: tree = etree.parse(文件名) tree.xpath("xpath表达式")
- 网络数据: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解析
- 环境的安装
- 需要将pip原设置为国内源,阿里源,豆瓣源,网易源等
- windows
- 打开文件资源管理器(文佳佳地址栏中)
- 地址栏上面输入 %appdata%
- 在这里建一个文件夹 pip
- 在pip文件夹里新建一个文件叫做pip.ini,内容如下写即可
- [global]
- timeout = 6000
- index-url = https://mirrors.aliyun.com/pypi/simple/
- trusted-host = mirrors.aliyun.com
- linux中:
- cd ~
- mkdir ~/.pip
- vi ~/.pip/pip.conf
- 编辑内容,和windows一样
- 需要安装:pip install bs4
-
- bs4在使用时候需要一个第三方的库, 把这个库也安装一下
- pip install lxml
- 基础使用
- 导包: from bs4 import BeautifulSoup
- 使用方式:可以将html文档,转化为BeautifulSoup对象,然后通过对象的方法 或者属性去查找指定节点的内容
- 转化本地文件: soup = BeautifulSoup(open("本地文件"), "lxml")
- 转化网络文件: soup = BeautifulSoup("字符串类型或者字节类型", "lxml")
- 打印soup对象显示内容为htnl文件中的内容
- BeautifulSoup知识点:
- 根据标签名查找:
- soup.a 只能查找第一符合要求的标签
- 获取属性:
- soup.a.attrs 获取所有属性和属性值,返回一个字典
- soup.a.attrs["href"] 获取href属性
- soup.a["href"] 也可以简写成这种形式
- 获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
- 注意,如果标签还有标签,那么string获取到的结果为None,而其他两个,可以获取文本内容
- find:找到第一个 符合要求的标签
- soup.find("a") 找到第一个符合要求的
- soup.find("a", title="xuexue")
- soup.find("a", alt="xuexue")
- soup.find("a", class="xuexue")
- soup.find("a", id="xuexue")
- find_all:找到所有符合 要求的标签
- soup.find_all("a")
- soup.find_all(["a","b"]) # 找到所有的a标签和b标签
- soup.find_all("a", limit=2) # 限制前两个
- 根据选择器选择指定的内容
- 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次的时候,就会在登录页面中生成验证码,通过验证码达到分流和反爬的效果
- 云打码处理平台是一个很好的处理验证码的平台
云打码平台处理验证码实现流程:
- 对携带验证码的页面数据进行爬取
- 可以将页面数据中验证码进行解析,验证码图片下载到本地
- 可以将 验证码图片提交给第三方平台进行识别,返回验证码图片上的数据值
- 云打码平台:
- 在官网中注册(普通用户和开发者用户)
- 登录开发者用户:
- 实例代码的下载
- 创建一个软件
- 使用实例代码中的源码文件中的代码进行修改,让其识别验证码图片中的数据值
- 云打码平台:
- 代码展示:
# 该函数调用了打码平台的相关的接口对指定的验证码图片进行识别,返回图片上的数据值
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")