需要准备的东西:
python基础, html, css
web请求过程分析
- 服务器的渲染:在服务器那边直接把数据和html整合在一起,统一返回给浏览器
- 在页面源代码中可以看到数据
- 客户端渲染:
- 第一次请求只要一个html骨架,第二次请求拿到数据,进行数据展示
- 在页面源代码中看不到数据
HTTP协议(超文本传输协议)
Http协议吧一条信息分为三大块内容,无论是请求还是相应都是三大块
请求:
1. 请求行 -> 请求方式 请求url地址 协议
2. 请求头 -> 放一些服务器要使用的附加信息
3. 请求体 -> 一般放一些请求参数
相应
1. 状态行 -> 协议 状态码
2. 响应头 -> 放一些客户端要使用的一些附加信息
3. 响应体 -> 服务器返回的真正客户端要使用的内容(Html, json)等
请求头中最常见的一些重要内容(爬虫需要):
- User-Agent:请求载体的身份标识(用啥发送的请求)
- Referer:防盗链(这次请求是从哪个页面来的,反爬会用到)
- cookie:本地字符串数据信息(用户登录信息,反爬的token)
响应头中一些重要的内容
- cookie:本地字符串数据信息(用户登录信息,反爬的token)
- 各种神奇的莫名存在的字符串(这个需要经验,一般都是token,放着各种攻击和反爬)
请求方式:
GET:显示提交
POST:隐式提交
数据解析概述
正则表达式
Regular Expression,正则表达式,一种使用表达式的方式对字符串进行匹配的语法规则
我们抓取到的网页源代码本质上就是一个超长的字符串,想从里面提取内容,则正则再适合不过了
正则优点:速度快,效率高,准确性高
正则的缺点:新手上手难度有点高
不过只要掌握了正则编写的逻辑关系,写出一个提取网页内容的正则其实并不复杂
正则语法:使用元字符进行排列组合用来匹配字符串,可以在正则表达式在线测试
元字符:具有固定含义的特殊符号
常用元字符
1. . 匹配除换行符以外的任意字符
2. \w 匹配字母或数字或下划线
3. \s 匹配任意的空白字符
4. \d 匹配数字
5. \n 匹配一个换行符
6. \t 匹配一个换行符
7. ^ 匹配字符串的开始
8. $ 匹配字符串的结尾
9. \W 匹配非字母或数字或下划线
10. \D 匹配非数字
11. \S 匹配非空白字符
12. a|b 匹配字符a或字符b
13. () 匹配括号内的表达式,也表示一个组
14. [...] 匹配字符组中的字符 // [a-zA-Z0-9]匹配a-z和A-Z和0-9之间的字符
15. [^...] 匹配处理除字符数组中字符的所有字符
一般一个元字符表示一个字符
一般和$配合使用:\d\d\d$
量词:控制前面的元字符出现的次数
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
贪婪匹配和惰性匹配
.* 贪婪匹配
.*? 惰性匹配
re表达式
-
findall:匹配字符串中所有的复合正则表达式的内容
- lst = re.findall(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010“)
- print(list) ====== ['10086', '10010'] // 使用findall返回的是一个列表
- lst = re.findall(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010“)
-
finditer:匹配字符串中所有的内容[返回一个迭代器],从迭代器中获取每个元素使用.group()
-
it = re.finditer(e"\d+", "我的电话号码是:10086, 我女朋友的电话号码是:10010“)
for i in it: print(i.group)
-
-
search,找到一个结果就返回,返回的结果是match对象,从中拿数据需要使用.group
- s = re.search(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010“)
- print(s.group) ======= 10086// 只返回一个结果
-
match 是从头开始匹配
- s = re.match(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010")
- print(s.group) === 会报错 ,因为s为空
- s = re.match(r"\d+","10086, 我女朋友的电话号码是:10010“)
- print(s.group) ==== 10086
-
预加载正则表达式(将正则表达式放在变量中)
obj = re.compile(r"\d+") ret = obj.finditer("我的电话号码是:10086, 我女朋友的电话号码是:10010") for it in ret: print(it.group)
-
通过正则表达式获取其中一部分东西
- 获取方法 :(?P<分组名字>正则表达式) 这样可以单独的从正则匹配的内容中进一步提取内容
s = """ <div class='jay'><span id='1'>郭麒麟</span></div> <div class='jj'><span id='2'>宋铁</span></div> <div class='jolin'><span id='3'>大聪明</span></div> <div class='sylar'><span id='4'>范思哲</span></div> <div class='tory'><span id='5'>喜羊羊</span></div> """ # 预加载正则表达式 obj = re.compile(r"<div class='.*?'><span id='\d'>(?P<name>.*?)</span></div>") result = obj.finditer(s) for it in result: print(it.group("name")) // 输出结果 郭麒麟 宋铁 大聪明 范思哲 喜羊羊
-
当我们在使用requests请求的时候如果报错的话,出现
exceptions.SSLError:HTTPSConnectionPool 这种情况,一般是requests函数内部检查出错,我们可以使用:
requests.get(url, verify=Flase) // verify = Flase 去掉安全验证
bs4解析
-
把页面源代码交给BeautifulSoup进行处理,生成bs对象
page = BeautifulSoup(resp.text,"html.parser")
-
从bs对象中查找数据
find(标签,属性=值) find_all(标签,属性=值) # 当我们使用属性 = 值的时候属性的名称可能和python中的关键字重名,这样会报错 # 现在给出一下解决方法 table = page.find("table", class_="hq_table") # 这里class属性名就和python中的关键字重复了,我们可以加下划线 # 另一种解决方法 table = page.fine("table", attrs={"class" : "hq_table"}) # 这种写法和上面的相同
-
".text"方法可以获取标签中包裹着的文本
-
".get('herf')" 获取标签的属性
xpath解析
xpath 是在XML文档中搜索内容的一门语言
html是XML的一个子集
Xpath寻找方式是从父节点,到子节点这样的方式寻找
<book>
<id>1</id>
<name>zhang</name>
<author>
<nick>周大强</nick>
<nick>周芷若</nick>
<div>
<nick>阿布</nick>
<nick>安安</nick>
</div>
<span>
<nick>大胖</nick>
</span>
</author>
</book>
# 寻找方式: /book/author/ nick 其中 “/” 表示层级关系,第一个 / 表示从根节点开始寻找 / 表示获取父节点的(儿子)
# /book/author/ nick/text() 这样就获取了nick中的文本了 text()表示获取文本
# 获取author里面的所有nick只通过 / 这个符是不行的 / 符只能一层层寻找不能够跨层寻找
# /book/author//nick/text() 这样就拿到author里面所有的nick了 // 表示获取父节点的后代(子孙)
# /book/author/*/nick/text() 这样就拿到author里面隔一个标签里面的nick了 * 通配符(任意节点)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li><a href="www.baidu.com">百度</a></li>
<li><a href="www.google.com">谷歌</a></li>
<li><a href="www.sougou.com">搜狗</a></li>
</ul>
<ol>
<li><a href="feiji">飞机</a></li>
<li><a href="dapao">大炮</a></li>
<li><a href="huoche">火车</a></li>
</ol>
<div class="job">李嘉诚</div>
<div class="common">胡辣汤</div>
</body>
</html>
# result = tree.xpath('/html')
# result = tree.xpath('/html/body/ul/li/a/text()') 寻找ul/li/a标签中所有的文本
# result = tree.xpath('/html/body/ul/li[1]/a/text()') 寻找ul/li中第一个li标签中的a标签 xpath顺序是从1开始的
# 下面这是个寻找ul/li/a标签中href为“dapao”的标签的文本 [@xxx = xxx] 表示属性的筛选
# result = tree.xpath('html/body/ol/li/a/[@href = "dapao"]/text()')
ol_li_list = tree.xpath("html/body/ol/li")
for li in ol_li_list:
# 从每个li中提取到文字信息
result = li.xpath("./a/text()") # 在li中继续寻找 使用 " . " 这个表示当前目录
result2 = li.xpaht('.a/@href') # 拿到属性值@ 属性
requests 进阶概述
模拟浏览器登录 ---> 处理cookie
# 登录 --> 得到cookie
# 带着cookie 去请求后台页面 --> 获取只有登录才能访问的页面
# 我们需要把上面的步骤连起来,保证cookie不会丢失
# 这里我们就可使用session进行请求 -> session请求你可以认为是一连串的请求,在这个过成功cookie,不会丢失
import requests
data = {
"loginName":""
"password":""
}
session = requsets.session()
# 1. 登录
url = "...."
# 通过session来请求页面,这样的话session就会记住cookie,方便我们下一步访问
resp = session.post(url, data = data)
# print(resp.cookies) # 看cookie
# 2.拿书架上的数据
# resp = requests.get(url = "...") !! 千万不要这样写,因为这样会向浏览器从新发送请求,会丢失cookie访问失败
# 我们使用session 来进行访问:
resp = session.get("....")
print(resp.json())
防盗链处理 --->抓取梨视频数据
防盗链的用途:就是在你访问这个页面之前,你必须访问referer指向的网址
页面源代码和F12中出现的代码可能是不同的,F12中出现的可能是动态加载的