1,正则解析:就是通过正则匹配定位到要获取数据的标签,获取响应的数据
- 直接上代码(以爬取糗事百科为例)
import requestsimport reimport osif __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 = '.*? .*?' 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 requestsfrom lxml import etreeimport base64from urllib import request# 指定要访问的urlurl = "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 requestsfrom 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次的时候,就会在登录页面中生成验证码,通过验证码达到分流和反爬的效果
- 云打码处理平台是一个很好的处理验证码的平台
云打码平台处理验证码实现流程:
- 对携带验证码的页面数据进行爬取
- 可以将页面数据中验证码进行解析,验证码图片下载到本地
- 可以将 验证码图片提交给第三方平台进行识别,返回验证码图片上的数据值
- 云打码平台:
- 在官网中注册(普通用户和开发者用户)
- 登录开发者用户:
- 实例代码的下载
- 创建一个软件
- 使用实例代码中的源码文件中的代码进行修改,让其识别验证码图片中的数据值
- 云打码平台:
- 代码展示:
# 该函数调用了打码平台的相关的接口对指定的验证码图片进行识别,返回图片上的数据值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 requestsfrom lxml import etreefrom urllib import request# 获取一个session对象session = requests.Session()# session对象和requests作用几乎一样,都可以进行请求的发送,并且请求发送的方式也是一样的# session进行请求的发送,如果会产生cookie的话 ,则cookie会自动被存储到session中# 获取验证码图片# 找到请求的urlurl = "http://www.renren.com/"# 找到请求的请求头UAheaders = { "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")