22.2.11爬虫基础和数据解析
1.web请求过程剖析:
-
服务器渲染:
-
在服务器那边直接把数据和HTML整合在一起,统一返回给浏览器,这种渲染方式在页面源码中看得到数据。
-
例如:在浏览器(客户端)中输入IU时,浏览器向服务器发送带有“IU”的请求,服务器会返回带有IU的经过整理后的HTML给浏览器(客户端)。
-
-
客户端渲染:
-
第一次请求时服务器只会返回一个HTML骨架,在第二次请求时才会拿到数据,进行数据展示。这种渲染方式在页面源码中看不到数据,只有找到了对应的URL才能看到数据。
-
2.HTTP协议:
-
HTTP协议将一条消息分为三块内容:
-
请求:
-
请求行:一般是请求方式(get/post),请求URL的地址,协议。。。。。。
-
请求头:存放一些服务器要使用的附加信息。
-
请求体:一般放一些请求参数。
-
-
响应:
-
响应行:协议,状态码(404,200.。。。。。。)
-
响应头:放客户端要使用的附加信息;
-
相应体:服务器返回的真正客户端要使用的内容(HTML,JSON等)。
-
-
-
请求头中常见重要内容:
-
user-Agent:请求载体的身份标识。
-
Referer:防盗链(这次请求是从哪个页面来,在反爬中常用)。
-
cookie:本地字符串中数据信息(用户登录信息,反爬的token)。
-
-
响应头中常见重要内容:
-
cookie:
-
一些字符串:一般是token字样,防止攻击和反爬。
-
-
请求方式:
-
get:显示提交,查询时多用。get是根据URL直接获取网页信息(即某个网址所包含的信息),get方法获取到的内容是稳定的(即每个人打开某个网页获得的信息相同)。get直接输入URL即可。
-
post:隐示提交,post是要携带用户信息的请求方式,post要获取的内容只靠网址是不能获取到的,需要提交一些额外的信息,这种信息在不同的网页中发挥不同功能。例如在查询天气的网页,可能就是要输入城市信息;在登录某些网页时,又是账号和密码的载体。post需要输入特定信息,那么得到的网页内容就会有特异性。post每次获取某个特定网页都需要输入额外信息
-
3.数据解析:
-
方式:
-
共有三种,分别为re解析,bs4解析,xpath解析。
-
re解析:
-
正则表达式:
-
1.元字符:
. 匹配除了换行符以外的任意字符
\w 匹配数字,字母,下划线
\s 匹配任意空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配输入字符串的开始位置
$ 匹配输入字符串的结束位置
\W 匹配除了数字字母下划线
\S 匹配非空白符
\D 匹配非数字
() 匹配并获得与括号内的表达式相匹配的串
[...] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^...] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中 的'p'、'l'、'i'、'n'。
2.量词:控制元字符出现的次数;
* 0次或更多次
+ 1次或更多次
? 0次或1次
{n} 重复n次
{n,} 重复>=n次
{n,m} 重复n到m次
3.贪婪匹配和惰性匹配:
(假设有字符串txzmytxzmytxzmy)
贪婪匹配: .* 尽可能匹配最远的 例如t.*y 对于上述字符串得到结果 txzmytxzmytxzmy
惰性匹配: .*? 尽可能匹配最近的 例如t.*?y 对于上述字符串得到结果 txzmy
-
-
re模块:
-
findall:匹配字符串中所有复合的内容。
-
finfiter:匹配字符串中所有复合的内容,返回值是一个迭代器,从迭代器中取得内容要用.group()
-
search:返回match对象,拿数据需要.group()
-
match:从头开始匹配。
-
-
预加载正则表达式:
-
obj = re.compile(r"正则表达式") #便于多次利用正则表达式。
补充:
(?P<名字>正则表达式) 可以拿到特别标识的(名字)内容
re.S 可以将不同行的字符串连接起来整体匹配
-
-
练习:
-
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 解决 InsecureRequestWarning: Unverified HTTPS request is being made to host(requests证书警告)
import selenium
import re
url = "https://dytt89.com/"
response = requests.get(url = url,verify=False)
response.encoding = "gb2312"
edge = response.text
obj = re.compile(r'2022新片精品.*? <ul>.*?彻底解决迅雷无法下载</font></a><span><font color="#FF0000">02-11</font></span></li>(?P<web>.*?) </div>',re.S)
res = obj.finditer(edge)
obj2 = re.compile(r"<a href='(?P<herf>.*?)' title="'(?P<title>.*?)'">",re.S)
obj3 = re.compile(r'<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<adress>.*?)">magnet')
for i in res:
url2 = i.group("web")
res2 = obj2.finditer(url2)
for j in res2:
print(j.group("title"))
print("下载地址 ")
url3 = url+j.group("herf").strip("/")
#print(url3)
response2 = requests.get(url3)
response2.encoding = "gb2312"
res3 = obj3.finditer(response2.text)
for k in res3:
print("'"+k.group("adress")+"'")
#在第二个for里面也可以将url3存在一个列表里 -
-
-
-
bs4解析:
-
bs4解析可以通过网页源码的标签来获得藏在网页源码中的数据。
-
bs4解析的流程:
-
先创建BeautifulSoup对象;
-
从对象中利用find("标签","limit")和find_all("标签","limit")找数据。
-
find_all和find的使用: 1、在提取标签的时候,第一个参数是标签的名字。如果在提取标签的时候想要使用标签属性进行过滤,那么可以在这个方法中通过关键字参数的形式,将属性的名字以及对应的值传进去,或者是使用attrs属性,将所有的属性以及对应的值放在一个字典中传给attrs属性。
2、有时,在提取标签的时候,不想提取那么多,可以使用limit参数限制提取个数。
find与find_all的区别: 1、find:找到第一个满足条件的标签就返回,只返回一个元素。 2、find_all:将所有满足条件的标签都返回,返回多个(以列表的形式)。 使用find和find_all的过滤条件: 1、关键字参数:将属性的名字作为关键字参数的名字,以及属性的值作为关键字参数的值进行过滤。 2、attrs参数:将属性条件放到一个字典中,传给attrs参数。
-
-
-
练习:
-
import re
from bs4 import BeautifulSoup
url = "http://www.netbian.com/"
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36"
}
response = requests.get(url)
response.encoding = "gbk"
#print(response.text)
bser = BeautifulSoup(response.text,"html.parser")
alist = bser.find("div",attrs={"class":"wrap clearfix"}).find_all("img")
#print(alist)
for a in alist:
print(a.get("src"))
-
-
-
xpath解析:
-
xpath解析是依靠节点之间的关系(主要是利用关系,也可以向上面的解析方式一样利用属性)查找数据。
-
相关的知识点:
-
xml格式:
-
xml格式包含html,调用xpath时传入的参数要对应,其格式大致如下:
-
。。。
<Teams>
<Member team="X" Description="X">
<name>灵动生活</name>
<position>planning</position>
</Member>
<Member team="Y" Description="Y">
<name>蓝蓝海天</name>
<position>support</position>
</Member>
<Member team="Z" Description="Z">
<name>神舟龙</name>
<position>lean</position>
</Member>
</Teams>
。。。 -
例如:拿到数据蓝蓝海天:
-
"Teams/Member[2]/name/text()"
text()可以拿到标签中的文字内容。
-
-
补充:
-
// 可以拿到后代中所有的
eg:
"Teams//name/text()"
能拿到灵动生活,蓝蓝海天,神州龙
[@... = ...] 属性筛选
eg:
"Teams/Member[@team = x]/name/text()"
能拿到灵动生活
相对路径查找:
假设省略号到达的路径为li = html.xpath("...一个html网页")
则name = li/xpath("./Teams/Member[@team = x]/name/text()")
要拿到"X":
则x = li/xpath("./Teams/Member/@team")
-
-
-
-
练习(爬取猪八戒网址):
-
import requests
from lxml import etree
url = "https://search.zbj.com/f/?type=new&kw=SaaS&fr=newpdy.it.20.8.04"
response = requests.get(url)
#print(response.text)
html = etree.HTML(response.text)
divs = html.xpath("/html/body/div[6]/div/div/div[2]/div[5]/div[1]/div")
for div in divs:
location = div.xpath("./div/div/a[1]/div[1]/div/span/text()")[0]
price = div.xpath("./div/div/a[2]/div/div[1]/span[1]/text()")[0].strip("¥")
appinfo = "saas".join(div.xpath("./div/div/a[2]/div/div[2]/p/text()"))
name = div.xpath("./div/div/a[1]/div[1]/p/text()")[1]
print(name)
print(appinfo)
print(price)
print(location)
-
-
-
-