共计 10511 个字符,预计需要花费 27 分钟才能阅读完成。
1.urllib 库
1.1 根本应用
应用 urllib 来获取百度首页的源码
import urllib.request
# 1、定义一个 url 就是你要拜访的地址
url = 'http://www.baidu.com'
# 2、模仿浏览器向服务器发送申请 response 响应
response = urllib.request.urlopen(url)
# 3、获取响应中的页面的源码
content = response.read().decode('utf-8')
# 4、打印数据
print(content)
read 办法,返回的是字节模式的二进制数据,咱们要将二进制的数据转换为字符串,需解码:decode(‘编码的格局’)
1.2 1 个类型和 6 个办法
import urllib.request
url = 'http://www.baidu.com'
# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(url)
# 一个类型:response 是 HTTPResponse 的类型
print(type(response))
# 依照一个字节一个字节的去读
content = response.read()
print(content)
# 返回多少个字节
content = response.read(5)
print(content)
# 读取一行
content = response.readline()
print(content)
# 一行一行读取 直至完结
content = response.readlines()
print(content)
# 返回状态码 如果是 200 了 那么就证实咱们的逻辑没有错
print(response.getcode())
# 返回的是 url 地址
print(response.geturl())
# 获取是一个状态信息
print(response.getheaders())
一个类型:HTTPResponse
六个办法:read、readline、readlines、getcode、geturl、getheaders
1.3 下载
import urllib.request
# 下载网页
url_page = 'http://www.baidu.com'
# url 代表的是下载的门路 filename 文件的名字
urllib.request.urlretrieve(url_page,'baidu.html')
# 下载图片
url_img = 'https://img1.baidu.com/it/u=3004965690,4089234593&fm=26&fmt=auto&gp=0.jpg'
urllib.request.urlretrieve(url= url_img,filename='lisa.jpg')
# 下载视频
url_video = 'https://vd3.bdstatic.com/mda-mhkku4ndaka5etk3/1080p/cae_h264/1629557146541497769/mda-mhkku4ndaka5etk3.mp4?v_from_s=hkapp-haokan-tucheng&auth_key=1629687514-0-0-7ed57ed7d1168bb1f06d18a4ea214300&bcevod_channel=searchbox_feed&pd=1&pt=3&abtest='
urllib.request.urlretrieve(url_video,'hxekyyds.mp4')
在 python 中,能够写变量的名字,也能够间接写值
1.4 申请对象的定制
import urllib.request
url = 'https://www.baidu.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
# 因为 urlopen 办法中不能存储字典 所以 headers 不能传递进去
# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf8')
print(content)
1.5 get 申请的 quote 办法
get 申请参数,如果是中文,须要对中文进行编码,如上面这样,如果不编码会报错。
需要 获取 https://www.baidu.com/s?wd= 周杰伦的网页源码
编码后如下:https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
import urllib.request
import urllib.parse
url = 'https://www.baidu.com/s?wd='
# 申请对象的定制为了解决反爬的第一种伎俩
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
# 将周杰伦三个字变成 unicode 编码的格局,须要依赖于 urllib.parse
name = urllib.parse.quote('周杰伦')
# 将转码后的字符串拼接到门路前面
url = url + name
# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)
# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)
# 获取响应的内容
content = response.read().decode('utf-8')
# 打印数据
print(content)
quote 实用于将中文转码成 Unicode 编码
1.6 get 申请的 urlencode 办法
urlencode 利用场景:多个参数的时候。如下
https://www.baidu.com/s?wd= 周杰伦 &sex= 男
# 获取 https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7 的网页源码
import urllib.request
import urllib.parse
base_url = 'https://www.baidu.com/s?'
data = {
'wd':'周杰伦',
'sex':'男',
'location':'中国台湾省'
}
new_data = urllib.parse.urlencode(data)
# 申请资源门路
url = base_url + new_data
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
# 申请对象的定制
request = urllib.request.Request(url=url,headers=headers)
# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)
# 获取网页源码的数据
content = response.read().decode('utf-8')
# 打印数据
print(content)
1.7 post 申请
import urllib.request
import urllib.parse
url = 'https://fanyi.baidu.com/sug'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
data = {'kw':'spider'}
# post 申请的参数,必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url,data=data,headers=headers)
# 模仿浏览器向服务器发送申请
response = urllib.request.urlopen(request)
# 获取响应的数据
content = response.read().decode('utf-8')
# 字符串 --》json 对象
import json
obj = json.loads(content)
print(obj)
post 申请的参数 必须要进行编码:data = urllib.parse.urlencode(data)
编码之后 必须调用 encode 办法:data = urllib.parse.urlencode(data).encode(‘utf-8’)
post 的申请的参数,是不会拼接在 url 的前面的,而是须要放在申请对象定制的参数中:
request = urllib.request.Request(url=url,data=data,headers=headers)
1.8 异样
import urllib.request
import urllib.error
url = 'http://www.doudan1.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
try:
request = urllib.request.Request(url = url, headers = headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
except urllib.error.HTTPError:
print('零碎正在降级。。。')
except urllib.error.URLError:
print('我都说了 零碎正在降级。。。')
1.9 handler
为什么要学习 handler?
- urllib.request.urlopen(url) 不能定制申请头
- urllib.request.Request(url,headers,data) 能够定制申请头
- Handler:定制更高级的申请头(随着业务逻辑的简单 申请对象的定制曾经满足不了咱们的需要,动静 cookie 和代理不能应用申请对象的定制)
# 需要 应用 handler 来拜访百度 获取网页源码
import urllib.request
url = 'http://www.baidu.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
request = urllib.request.Request(url = url,headers = headers)
# handler build_opener open
#(1)获取 hanlder 对象
handler = urllib.request.HTTPHandler()
#(2)获取 opener 对象
opener = urllib.request.build_opener(handler)
# (3) 调用 open 办法
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
1.10 代理
为什么须要代理?因为有的网站是禁止爬虫的,如果用实在的 ip 去爬虫,容易被封掉。
import urllib.request
url = 'http://www.baidu.com/s?wd=ip'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
# 申请对象的定制
request = urllib.request.Request(url = url,headers= headers)
# 模仿浏览器拜访服务器
# response = urllib.request.urlopen(request)
proxies = {'http':'118.24.219.151:16817'}
# handler build_opener open
handler = urllib.request.ProxyHandler(proxies = proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
# 获取响应的信息
content = response.read().decode('utf-8')
# 保留
with open('daili.html','w',encoding='utf-8')as fp:
fp.write(content)
代理能够应用:快代理。能够应用代理池来代替一个代理
2. 解析技术
2.1 xpath
xpath 装置及加载
1. 装置 lxml 库
pip install lxml ‐i https://pypi.douban.com/simple
2. 导入 lxml.etree
from lxml import etree
3.etree.parse() 解析本地文件
html\_tree = etree.parse(‘XX.html’)
4.etree.HTML() 服务器响应文件
html\_tree = etree.HTML(response.read().decode(‘utf‐8’)
5. 解析获取 DOM 元素
html\_tree.xpath(xpath 门路)
依照 xpath 的 chrome 插件,应用 ctrl + shift + x 关上插件
xpath 根本语法
1. 门路查问
//:查找所有子孙节点,不思考层级关系
/:找间接子节点
2. 谓词查问
//div[@id]
//div[@id=“maincontent”]
3. 属性查问
//@class
4. 含糊查问
//div[contains(@id,“he”)]
//div[starts‐with(@id,“he”)]
5. 内容查问
//div/h1/text()
6. 逻辑运算
//div[@id=“head”and @class=“s\_down”]
//title | //price
示例:
from lxml import etree
# xpath 解析本地文件
tree = etree.parse('test.html')
# 查找 ul 上面的 li
li_list = tree.xpath('//body/ul/li')
# 查找所有有 id 的属性的 li 标签,text() 获取标签中的内容
li_list = tree.xpath('//ul/li[@id]/text()')
# 找到 id 为 l1 的 li 标签 留神引号的问题
li_list = tree.xpath('//ul/li[@id="l1"]/text()')
# 查找到 id 为 l1 的 li 标签的 class 的属性值
li = tree.xpath('//ul/li[@id="l1"]/@class')
# 查问 id 中蕴含 l 的 li 标签
li_list = tree.xpath('//ul/li[contains(@id,"l")]/text()')
# 查问 id 的值以 l 结尾的 li 标签
li_list = tree.xpath('//ul/li[starts-with(@id,"c")]/text()')
#查问 id 为 l1 和 class 为 c1 的
li_list = tree.xpath('//ul/li[@id="l1"and @class="c1"]/text()')
li_list = tree.xpath('//ul/li[@id="l1"]/text() | //ul/li[@id="l2"]/text()')
2.2 JsonPath
JsonPath 只能解析本地文件。
jsonpath 的装置及应用
pip 装置:
pip install jsonpath
jsonpath 的应用:
obj = json.load(open(‘json 文件’,‘r’, encoding=‘utf‐8’))
ret = jsonpath.jsonpath(obj,‘jsonpath 语法’)
示例:
{
"store": {
"book": [
{
"category": "修真",
"author": "六道",
"title": "坏蛋是怎么练成的",
"price": 8.95
},
{
"category": "修真",
"author": "天蚕土豆",
"title": "斗破天穹",
"price": 12.99
},
{
"category": "修真",
"author": "唐家三少",
"title": "斗罗大陆",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "修真",
"author": "南派三叔",
"title": "星辰变",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"author": "老马",
"color": "彩色",
"price": 19.95
}
}
}
解析下面的 json 数据
(https://links.jianshu.com/go?…)
import json
import jsonpath
obj = json.load(open('jsonpath.json','r',encoding='utf-8'))
# 书店所有书的作者
author_list = jsonpath.jsonpath(obj,'$.store.book[*].author')
# 所有的作者
author_list = jsonpath.jsonpath(obj,'$..author')
# store 上面的所有的元素
tag_list = jsonpath.jsonpath(obj,'$.store.*')
# store 外面所有货色的 price
price_list = jsonpath.jsonpath(obj,'$.store..price')
# 第三个书
book = jsonpath.jsonpath(obj,'$..book[2]')
# 最初一本书
book = jsonpath.jsonpath(obj,'$..book[(@.length-1)]')
# 后面的两本书
book_list = jsonpath.jsonpath(obj,'$..book[0,1]')
book_list = jsonpath.jsonpath(obj,'$..book[:2]')
# 条件过滤须要在()的后面增加一个?# 过滤出所有的蕴含 isbn 的书。book_list = jsonpath.jsonpath(obj,'$..book[?(@.isbn)]')
# 哪本书超过了 10 块钱
book_list = jsonpath.jsonpath(obj,'$..book[?(@.price>10)]')
2.3 BeautifulSoup
根本介绍
- BeautifulSoup 简称:bs4
- 什么是 BeatifulSoup?BeautifulSoup,和 lxml 一样,是一个 html 的解析器,次要性能也是解析和提取数据
-
优缺点
毛病:效率没有 lxml 的效率高
长处:接口设计人性化,使用方便
装置以及创立
-
装置
pip install bs4 -i https://pypi.douban.com/simple
-
导入
from bs4 import BeautifulSoup
-
创建对象
-
服务器响应的文件生成对象
soup = BeautifulSoup(response.read().decode(),‘lxml’)
-
本地文件生成对象
soup = BeautifulSoup(open(‘1.html’),‘lxml’)
-
留神:默认关上文件的编码格局 gbk 所以须要指定关上编码格局
节点定位
1. 依据标签名查找节点
soup.a # 只能找到第一个 a
soup.a.name
soup.a.attrs
2. 函数
-
find(返回一个对象)
find(‘a’):只找到第一个 a 标签
find(‘a’, title=‘名字’)
find(‘a’, class\_=‘名字’)
-
find\_all(返回一个列表)
find\_all(‘a’):查找到所有的 a
find\_all([‘a’,‘span’]) 返回所有的 a 和 span
find\_all(‘a’, limit=2) 只找前两个 a
-
select(依据选择器失去节点对象)【☆☆☆】
element
:p.class
:.firstname#id
:#firstname属性选择器
:[attribute]
:li = soup.select(‘li[class]’)[attribute=value]
:li = soup.select(‘li[class=“hengheng1”]’)层级选择器
:
div p 后辈选择器
div>p 子代选择器:某标签的第一级子标签
div,p div 或 p 标签的所有的对象
节点信息
-
获取节点内容:实用于标签中嵌套标签的构造
obj.string
obj.get\_text()【举荐】
-
节点的属性
tag.name:获取标签名
tag.attrs:将属性值作为一个字典返回
-
获取节点属性
obj.attrs.get(‘title’)【罕用】
obj.get(‘title’)
obj[‘title’]
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<ul>
<li id="l1"> 张三 </li>
<li id="l2"> 李四 </li>
<li> 王五 </li>
<a href=""id="" class="a1"> 尚硅谷 </a>
<span> 嘿嘿嘿 </span>
</ul>
</div>
<a href=""title="a2"> 百度 </a>
<div id="d1">
<span>
哈哈哈
</span>
</div>
<p id="p1" class="p1"> 呵呵呵 </p>
</body>
</html>
应用 BeautifulSoup 解析下面的 html
from bs4 import BeautifulSoup
# 默认关上的文件的编码格局是 gbk,所以在关上文件的时候须要指定编码
soup = BeautifulSoup(open('bs4 的根本应用.html',encoding='utf-8'),'lxml')
# 依据标签名查找节点,找到的是第一个符合条件的数据
print(soup.a)
# 获取标签的属性和属性值
print(soup.a.attrs)
# bs4 的一些函数
#(1)find:返回的是第一个符合条件的数据
print(soup.find('a'))
# 依据 title 的值来找到对应的标签对象
print(soup.find('a',title="a2"))
# 依据 class 的值来找到对应的标签对象 留神的是 class 须要增加下划线
print(soup.find('a',class_="a1"))
#(2)find_all 返回的是一个列表,并且返回了所有的 a 标签
print(soup.find_all('a'))
# 如果想获取的是多个标签的数据 那么须要在 find_all 的参数中增加的是列表的数据
print(soup.find_all(['a','span']))
# limit 的作用是查找前几个数据
print(soup.find_all('li',limit=2))
#(3)select(举荐)# select 办法返回的是一个列表,并且会返回多个数据
print(soup.select('a'))
# 能够通过. 代表 class 咱们把这种操作叫做类选择器
print(soup.select('.a1'))
print(soup.select('#l1'))
# 属性选择器:通过属性来寻找对应的标签
# 查找到 li 标签中有 id 的标签
print(soup.select('li[id]'))
# 查找到 li 标签中 id 为 l2 的标签
print(soup.select('li[id="l2"]'))
# 层级选择器
# 后辈选择器:找到的是 div 上面的 li
print(soup.select('div li'))
# 子代选择器:某标签的第一级子标签
print(soup.select('div > ul > li'))
# 找到 a 标签和 li 标签的所有的对象
print(soup.select('a,li'))
# 获取节点内容
obj = soup.select('#d1')[0]
# 如果标签对象中,只有内容,那么 string 和 get_text() 都能够应用
# 如果标签对象中,除了内容还有标签,那么 string 就获取不到数据 而 get_text() 是能够获取数据
# 举荐应用 get_text()
print(obj.string)
print(obj.get_text())