python_chapter2_爬虫(Re正则表达式、Re模块补充、豆瓣实例、子页面获取下载地址实例、Bs4、Xpath)
在这里得感谢,B站up主路飞学城IT提供的优秀视频,此文章仅作为学习笔记,进行记录和分享…
python,爬虫(给兄弟们挂个🔗)
python边写边更…
一、数据解析概述:
若是服务器渲染,服务器会把 (html页面源码 + 数据) 放在一起 传回给 “浏览器”;而我们只想要,其中的一部分数据;这就涉及到数据抓取的问题;
有三种解析方式:
解析方式 | Re解析、bs4解析、xpath解析 |
---|
二、Re解析:
1.re正则:
(之前在舍友的硬盘里,白嫖到Alex16年的自动化python课程 /滑稽/滑稽/滑稽,在模块那章讲的re,讲的很好…课下我也更了文章…大家可以看下,有问题相互交流)
传送门
(Re正则表达式,在这篇文章的最后一部分…)
三、Re模块补充:
(1)对之前写的文章,不足的进行了补充…
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
#1.返回匹配到正则表达式的所有内容;
res = re.findall(r"\d+","我的电话号码是10010,她的电话号码是10086")
print(res)
#2.返回匹配到正则表达式的所有内容[返回的迭代器];从迭代器中拿到内容需要“.group()”
res = re.finditer(r"\d+","我的电话号码是10010,她的电话号码是10086")
for i in res:
print(i.group())
res = re.search(r"\d+","我的电话号码是10010,她的电话号码是10086")#也是迭代器;
print(res.group())
#3.预加载正则表达式;
obj = re.compile('\d+')
res = obj.finditer("我的电话号码是10010,她的电话号码是10086")
for i in res:
print(i.group())
conclude:
语法 | 实现 |
---|---|
re.finditer | 和findall一样,变成迭代器; |
print(obj.group()) | 从迭代器里面拿取到“数据” |
obj = re.complie("\d+") | 正则预编译,可以进行“点调用”; |
(2)简单实例:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
s = """
<div name='西游记'><span id='1'>蔡许坤</span></div>
<div name='三国演义'><span id='2'>马包国</span></div>
<div name='水浒传'><span id='3'>药水哥</span></div>
<div name='红楼梦'><span id='4'>糖果超甜</span></div>
"""
#(?P<分组名字>正则运算符);
obj = re.compile(r"<div name='(?P<book_name>.*?)'><span id='(?P<id>\d+)'>(?P<name>.*?)</span></div>",re.S)
#re.S...标记符,使“.”可以匹配到“换行符”,此时的“.”;
rsp = obj.finditer(s)
for i in rsp:
print(i.group("book_name"))#按分组名,进行分组;
conclude:
方法 | 实现功能 |
---|---|
(?P<>.*?) | 装逼专用,分组 |
re.S | 使“.”可以匹配到换行符; |
四、手刃豆瓣排行榜实例:
1.requests + re :
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re,requests
#Requests
page_str = input("你想爬取内容的页数:")
page_number = int(page_str)*25 #start,每页25个
ur = "https://movie.douban.com/top250"
par = {"start": page_number,"filter":"" }
hea={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.49"}
#1.开始爬取:
res = requests.get(url=ur,params=par,headers=hea )
print(res.text,type(res.text))#2.输出爬取文本
#Re
s = res.text
obj =re.compile(r'<li>.*?<span class="title">(?P<book_name>.*?)</span>.*?<p class="">.*?'
r'(?P<year>\d+) / (?P<city>.*?) / (?P<class>.*?)</p>'
r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>.*?<span>(?P<people_num>\d+)人评价</span>.*?</li>',re.S)
'''
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
r'</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?<span '
r'class="rating_num" property="v:average">(?P<score>.*?)</span>.*?'
r'<span>(?P<num>.*?)人评价</span>', re.S)'''
data = obj.finditer(s)
for i in data:
print(i.group("book_name").strip())
print(i.group("year").strip())
print(i.group("score").strip())
print(i.group("people_num").strip())
(页数每也都是25个,所以start是25的倍数…)
2.导入到csv文件 :
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re,requests
import csv
#Requests
page_str = input("你想爬取内容的页数:")
page_number = int(page_str)*25 #start,每页25个
ur = "https://movie.douban.com/top250"
par = {"start": page_number,"filter":"" }
hea={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.49"}
#1.开始爬取:
res = requests.get(url=ur,params=par,headers=hea )
print(res.text,type(res.text))#2.输出爬取文本
f = open("data.csv",mode = "w",encoding="utf-8")
csv_obj = csv.writer(f)#点调用
#Re
s = res.text
obj =re.compile(r'<li>.*?<span class="title">(?P<book_name>.*?)</span>.*?<p class="">.*?'
r'(?P<year>\d+) / (?P<city>.*?) / (?P<class>.*?)</p>'
r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>.*?<span>(?P<people_num>\d+)人评价</span>.*?</li>',re.S)
'''
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
r'</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?<span '
r'class="rating_num" property="v:average">(?P<score>.*?)</span>.*?'
r'<span>(?P<num>.*?)人评价</span>', re.S)'''
data = obj.finditer(s)
for i in data:
dic = i.groupdict()#把数据生成字典;
dic['year'] = dic['year'].strip()
dic['class'] = dic['class'].strip()
csv_obj.writerow(dic.values())
print("over!")
csv文件 | 操作 |
---|---|
导入模块 | import csv |
生成一个句柄 | obj = csv.writer(f) |
开始写入 | obj.writerow(values) |
生成字典 | |
---|---|
1. | it.groupdic() |
2. | obj.writerow(dic.values) |
五、子页面获取下载地址实例:
step1:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#1.定位到2020必看热片;
#2.从2020必看片中,提取到子页面的链接地址;
#3.请求子页面的链接地址,拿到我们想要的下载地址....
import requests,re
url = "https://www.dytt89.com/"
resp = requests.get(url,verify = False) #verify =false 去掉安全认证
resp.encoding="gb2312"#按照gb2313解码,gbk向下兼容gb2312;
print(resp.text)
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<child_page>.*?)",re.S)
obj1.search(resp.text)
step2:
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<child_page>.*?)</ul>",re.S)
resp1 = obj1.search(resp.text)#一次查询,生成迭代器;
print(resp1.group())
step3:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#1.定位到2020必看热片;
#2.从2020必看片中,提取到子页面的链接地址;
#3.请求子页面的链接地址,拿到我们想要的下载地址....
#1.拿到子页面信息;
import requests,re
url = "https://www.dytt89.com/"
resp = requests.get(url,verify = False) #verify =false 去掉安全认证
resp.encoding="gb2312"#按照gb2313解码,gbk向下兼容gb2312;
#print(resp.text)
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<child_page>.*?)</ul>",re.S)
resp1 = obj1.search(resp.text)#一次查询,生成迭代器;
#print()
str1 =resp1.group()
#print(str1,type(str1))
#2.进入到子页面,(触发新的url请求);
obj2 = re.compile(r"<a href='(?P<href>.*?)'",re.S)#拿到所有的href;
child_resp = obj2.finditer(str1)
for i in child_resp:
print(i.group())
step4:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#1.定位到2020必看热片;
#2.从2020必看片中,提取到子页面的链接地址;
#3.请求子页面的链接地址,拿到我们想要的下载地址....
#1.拿到子页面信息;
import requests,re
url = "https://www.dytt89.com/"
resp = requests.get(url,verify = False) #verify =false 去掉安全认证
resp.encoding="gb2312"#按照gb2313解码,gbk向下兼容gb2312;
#print(resp.text)
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<child_page>.*?)</ul>",re.S)
resp1 = obj1.search(resp.text)#一次查询,生成迭代器;
#print()
str1 =resp1.group()
#print(str1,type(str1))
#2.进入到子页面,(触发新的url请求);
obj2 = re.compile(r"<a href='(?P<href>.*?)'",re.S)#拿到所有的href;
child_resp = obj2.finditer(str1)
child_list = []#准备你空列表;
for i in child_resp:
#进入子页面;
url2 = url+ i.group("href").strip("/")
#print(i.group("href"))
child_list.append(url2)#把子连接存放起来;
#3.获取子页面内容;
for j in child_list:
child_resp2 = requests.get(j,verify = False)#取消安全热认证;
child_resp2.encoding = "gb2312"
#print(child_resp2.text)#输出一个
obj3 = re.compile(r'◎片 名(?P<name>.*?)<br />.*?<ul> <li><a href="(?P<BD国语双字>.*?)".*?</a></li>',re.S)
child_name =obj3.search(child_resp2.text)
print(child_name.group("name"))
print(url2+child_name.group("BD国语双字").strip("/"))
#break#测试,循环一次;
conclude:
1.老师这个写的很简单…你可以自己完善一下…加上input或者自己搞个“面向对象”去实现;
2.只需要记住这两点:
verfiy = Flase | 取消安全验证 |
href | 存放子连接、超链接的地址 |
六、BS4前析-HTML语法规则:
1.标签语言:
(enen…你别看在网页上会有什么图片、链接、地址…但是,服务器给你的是源代码都是一些HTML超文本…而这些 “超文本”用的都是“标签语言”…下面老师让我大概了解了一下什么是“标签语言”)
标签语言:1.标签 2. 属性 3. 属性值
标签 | 功能 |
---|---|
< h1> </ h1> | 变粗、变大(一级标签) |
< h2> </ h2> | 二级标签 |
p | 段落 |
font | 字体(被废弃了,但能用) |
body | 主体 |
<标签 属性="值" 属性="值">
被标记的内容
</标签>
2.解析入门之搞菜价:
(url:北京生发地…用bs4这种标签语言,去爬取菜价…)
#1.拿到页面源代码;
#2.使用bs4进行解析,拿到数据;
import requests
from bs4 import BeautifulSoup
import csv
f = open("caijia.csv",mode="w",encoding="utf-8")
obj = csv.writer(f)
url = "http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml"
resp = requests.get(url)
#print(resp.text)#可以拿到...
#3.把页面HTML源代码,交给beautifulsoup进行处理,生成bs对象;
page = BeautifulSoup(resp.text,"html.parser")#指定HTML解析器
#4.从bs对象中查找数据;
#find(标签,属性);
#find_all;
#data1 = page.find("table",class_ = "hq_table")#class是python 的关键字 ,用class_代替;
data = page.find("table",attrs= {"class":"hq_table"})#和上面的等价操作,避免使用“class”
#print(data)
data1 = data.find_all("tr")[1:]#tr是行的意思,切片拿到一行一行的纯数据;
#print(data1)
for i in data1:
data3 = i.find_all("td")#(每一行拿每个的单个数据)
name = data3[0].text#拿到被标签标记的数据;
low_price = data3[1].text#最低价
average = data3[2].text#平均
high_price = data3[3].text#最高价
size= data3[4].text#规格
danwei = data3[5].text#单位
time = data3[6].text#日期
obj.writerow([name,low_price,average,high_price,size,danwei,time])
print("finish!!!")
step | 操作 |
---|---|
1.生成html | resp.text |
2.Beautifulsoup(resp.text , “html.parse”) | 使用html解释器; |
3.bs4对象进行 | find(标签,属性)、find_all() |
4.“tr” | 代表表格中的每一个“行”; |
5.“text” | 被标签标记的“内容” |
3.解析入门之抓图片:
url =“https://pic.netbian.com/”
(html下面的“子页面”)
子页面下的img -> 找到scr(下载地址)
import requests,time
from bs4 import BeautifulSoup
url = "https://pic.netbian.com/"
resp = requests.get(url)
resp.encoding = "gbk"
#print(resp.text)
obj = BeautifulSoup(resp.text,"html.parser")
child_page = obj.find("div", class_="slist")#进一步缩小范围
#print(child_page)
#抓住子连接;
alist = child_page.find_all("a")
#print(alist)
# for i in child_page:
for i in alist:
child_href = url+i.get("href")#得到属性;
#进去子页面
child_resp = requests.get(child_href)
child_resp.encoding = "gbk"
#从子页面里面拿到下载路径:
down_path = BeautifulSoup(child_resp.text,"html.parser").find("div", class_="photo-pic")
#找到img
img = down_path.find("img")
down_img = img.get("src")#下载地址;
print(down_img)
#下载图片
hearder = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.51"}
img_resp = requests.get(url + down_img,hearder)
#img_resp.content #这里拿到的是字节;
img_name = down_img.split("/")[-1]#拿到url中的最后一个内容;
with open ("img/"+img_name,mode = "wb") as f:
f.write(img_resp.content)#图片内容写入文件
print("%s finish downing。。。"%(img_name))
time.sleep(1)
print("all finishing、、、")
bs4 | 属性 |
---|---|
child_href = i.get(“href”) | 得到相应的属性 |
下载文件 | 操作 |
---|---|
requests.get(src) | 拿到resp |
f.write(resp.content) | 写成字节文件 |
![](https://img-blog.csdnimg.cn/20210502191557979.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDk0MTM4NQ==,size_5,color_FFFFFF,t_70)
(将文件夹中的索引去掉;)
七、Xpath前析-HTML语法规则:
Xpath是xml里面搜索内容的一门语言;
html是xml的一个子集合;子节点、父节点、根节点…
1.安装“lxml”模块,里面要用到etree方法;
(cmd 切到 python/scripts 路径下…)
pip install lxml
2.xpath的基本语法:
1.操作一:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from lxml import etree
obj_1 = """
<book>
<id>1</id>
<name>野花遍地⾹</name>
<price>1.23</price>
<nick>臭⾖腐</nick>
<author>
<nick id="10086">周⼤强</nick>
<nick id="10010">周芷若</nick>
<nick class="joy">周杰伦</nick>
<nick class="jolin">蔡依林</nick>
<div>
<nick>惹了</nick>
<div>
<nick>惹了1111</nick>
</div>
</div>
<span>
<nick>惹了1111</nick>
</span>
</author>
<partner>
<nick id="ppc">胖胖陈</nick>
<nick id="ppbc">胖胖不陈</nick>
</partner>
</book>
"""
#寻找路径,etree.xml(对象).xpath
test = etree.XML(obj_1).xpath("/book")#"/"表示层级关系,第一个/是根节点;
#test = etree.XML(obj_1).xpath("/book/name")
test_1 = etree.XML(obj_1).xpath("/book/name/text()")#text()拿文本;
test_2 = etree.XML(obj_1).xpath("/book/author/nick/text()")#text()拿文本;
test_3 = etree.XML(obj_1).xpath("/book/author//nick/text()")#author里面的后代,全部找到;
test_4 = etree.XML(obj_1).xpath("/book/author/*/nick/text()")#*任意节点的通配符;
test_5 = etree.XML(obj_1).xpath("/book//nick/text()")#所有的nick里面的内容;
print(test)
print(test_1)
print(test_2)
print(test_3)
print(test_4)
print(test_5)
操作 | 意义 |
---|---|
etree.XML(file.xml).xpath(路径) | 在路径下搜索文件file.xml里的内容; |
1.xpath(/book) | 第一个“/”代表的是,根节点; |
2.xpath(/book//nick) | "后代"操作,book下面的所有nick全部找出来; |
3.xpath(/book/*/nick) | “/*”通配符,代表所有的节点; |
4.xpath(/book/test()) | test()是取内容的操作 |
2.操作二:
(先写一个“test.html”测试文件…)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<ul>
<li><a href="http://www.baidu.com">百度</a></li>
<li><a href="http://www.google.com">⾕歌</a></li>
<li><a href="http://www.sogou.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>
(下面是python操作文件…)
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from lxml import etree
#输出所有的;
obj = etree.parse("test.html").xpath("/html/body/ul/li/a/text()")
print(obj)
#我只想要第一个li里面a标签的东西;
obj_1 = etree.parse("test.html").xpath("/html/body/ul/li[1]/a/text()")
print(obj_1)
#符合某种属性的筛选;
obj_2 = etree.parse("test.html").xpath("/html/body/ol/li/a[@href = 'dapao']/text()")
print(obj_2)
#遍历查询;
ol_li_list = etree.parse("test.html").xpath("/html/body/ol/li")
for i in ol_li_list:
#从每一个li中提取到文字信息;
obj_3 = i.xpath("./a/text()")# "./"表示从当前的节点往下找;
print(obj_3)
#从每一个li中提取到属性信息;
obj_4 = i.xpath("./a/@href")# "@href"从a标签里面拿到属性;
print(obj_4)
操作 | 意思 |
---|---|
1.xpath("/html/body/ul/li[1]/a/text()") | 取第一个内容; |
2.xpath("/html/body/ol/li/a[@href = ‘dapao’]/text()") | 取属性值符合的内容; |
3.xpath("./") | "./"是从当前的节点往下查询; |
4.xpath("./a/text()") | text()…取内容; |
5.xpath("./a/@href") | “@href”取属性值; |
(下面是个“分屏”的小技巧,之前不知道;看老师操作了就截了下来…)
(下面的小技巧是老师重点提到的…)
1.下面是Elements操作:
(鼠标滚动会“一一对应”)
2.可以拷贝…xpath(/…/…)
conclude:
1.etree.XML().xpath();
2.xpath("//nick"),“后代"操作;
3.xpath(”/*/"),匹配符;
4.xpath(“test()”),匹配内容;
5.xpath(’’@href’’),匹配属性;
3.猪八戒网xpath实例操作:
(选入第一个窗口…进行"右键"检查…在Element上面可以看见div标签的"分层")
(1.这里可以copy"xpath路径")
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#拿取页面源代码;
#提取和解析数据;
import requests
from lxml import etree
url = "https://shanxi.zbj.com/search/f/?type=new&kw=工作"
resp = requests.get(url)
#print(resp.text)
resp_obj = resp.text#生成html文件对象;
#提取和解析数据;
#1.所有的divs:
divs= etree.HTML(resp_obj).xpath("/html/body/div[6]/div/div/div[2]/div[6]/div[1]/div")
#2.遍历每个div;
for i in divs:
obj_1 = i.xpath("./div/div/a[1]/div[2]/div[1]/span[1]/text()")[0].strip("¥")#找到每个div里面的价格;
obj_2 = "工作".join(i.xpath("./div/div/a[1]/div[2]/div[2]/p/text()"))#找到每个div里面的标题;
obj_3 = i.xpath("./div/div/a[2]/div[1]/p/text()")[0]#找到每个div里面的运营商;
obj_4 = i.xpath("./div/div/a[2]/div[1]/div/span/text()")[0]#找到每个div里面的地址;
print(obj_1)
print(obj_2)
print(obj_3)
print(obj_4)
print("-------------")
(2.这里可以直接copy),然后稍微改动一下…
#这里粘贴的代码是不一样的,需要稍微改动....
//*[@id="utopia_widget_51"]/a[1]/div[2]/div[1]/span[1]
(上述的代码改为…以下),就是定位的id在往上数到 i 定位的地方;
./div/div/a[1]/div[2]/div[1]/span[1]
//*[@id="utopia_widget_51"]/a[1]/div[2]/div[1]/span[1]
(你会发现,这个和之前的那个"路径",一模一样…)