爬虫笔记

需要准备的东西:

python基础, html, css

web请求过程分析

  1. 服务器的渲染:在服务器那边直接把数据和html整合在一起,统一返回给浏览器
    • 在页面源代码中可以看到数据
  2. 客户端渲染:
    • 第一次请求只要一个html骨架,第二次请求拿到数据,进行数据展示
    • 在页面源代码中看不到数据

HTTP协议(超文本传输协议)

Http协议吧一条信息分为三大块内容,无论是请求还是相应都是三大块

请求:

1. 请求行 -> 请求方式	请求url地址	协议
2. 请求头 -> 放一些服务器要使用的附加信息
3. 请求体 -> 一般放一些请求参数

相应

1. 状态行 -> 协议 状态码
2. 响应头 -> 放一些客户端要使用的一些附加信息
3. 响应体 -> 服务器返回的真正客户端要使用的内容(Html, json)等

请求头中最常见的一些重要内容(爬虫需要):

  1. User-Agent:请求载体的身份标识(用啥发送的请求)
  2. Referer:防盗链(这次请求是从哪个页面来的,反爬会用到)
  3. cookie:本地字符串数据信息(用户登录信息,反爬的token)

响应头中一些重要的内容

  1. cookie:本地字符串数据信息(用户登录信息,反爬的token)
  2. 各种神奇的莫名存在的字符串(这个需要经验,一般都是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表达式

  1. findall:匹配字符串中所有的复合正则表达式的内容

    • lst = re.findall(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010“)
      • print(list) ====== ['10086', '10010'] // 使用findall返回的是一个列表
  2. finditer:匹配字符串中所有的内容[返回一个迭代器],从迭代器中获取每个元素使用.group()

    1. it = re.finditer(e"\d+", "我的电话号码是:10086, 我女朋友的电话号码是:10010“)

      for i in it:
      	print(i.group)
      
  3. search,找到一个结果就返回,返回的结果是match对象,从中拿数据需要使用.group

    • s = re.search(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010“)
    • print(s.group) ======= 10086// 只返回一个结果
  4. match 是从头开始匹配

    • s = re.match(r"\d+","我的电话号码是:10086, 我女朋友的电话号码是:10010")
    • print(s.group) === 会报错 ,因为s为空
    • s = re.match(r"\d+","10086, 我女朋友的电话号码是:10010“)
    • print(s.group) ==== 10086
  5. 预加载正则表达式(将正则表达式放在变量中)

    obj = re.compile(r"\d+")
    
    ret = obj.finditer("我的电话号码是:10086, 我女朋友的电话号码是:10010")
    for it in ret:
        print(it.group)
    
  6. 通过正则表达式获取其中一部分东西

    • 获取方法 :(?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"))
    // 输出结果
    郭麒麟
    宋铁
    大聪明
    范思哲
    喜羊羊
    
    
  7. 当我们在使用requests请求的时候如果报错的话,出现

    exceptions.SSLError:HTTPSConnectionPool 这种情况,一般是requests函数内部检查出错,我们可以使用:

    requests.get(url, verify=Flase) // verify = Flase 去掉安全验证

bs4解析

  1. 把页面源代码交给BeautifulSoup进行处理,生成bs对象

    page = BeautifulSoup(resp.text,"html.parser")

  2. 从bs对象中查找数据

    find(标签,属性=值)
    find_all(标签,属性=值)
    # 当我们使用属性 = 值的时候属性的名称可能和python中的关键字重名,这样会报错
    # 现在给出一下解决方法
    table = page.find("table", class_="hq_table") # 这里class属性名就和python中的关键字重复了,我们可以加下划线
    # 另一种解决方法
    table = page.fine("table", attrs={"class" : "hq_table"}) # 这种写法和上面的相同
    
  3. ".text"方法可以获取标签中包裹着的文本

  4. ".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中出现的可能是动态加载的

代理 ---->防止别封ip

上一篇:谷歌浏览器Chrome 80版本默认SameSite导致跨域请求Cookie丢失


下一篇:Bzoj[Usaco2018 Feb]5194 Snow Boots(线段树)