02 爬虫数据解析之re,xpath,beautifulsoup
一.正则匹配
简单用法演示:
1 字符: 2 print(re.findall(".","abccc31223dn哈哈")) ### . 匹配除了换行符以外的任意字符,搭配re.S可搭配任意字符(包括空行)#['a', 'b', 'c', 'c', 'c', '3', '1', '2', '2', '3', 'd', 'n', '哈', '哈'] 3 print(re.findall("ab[c,d]f","ab,f")) #匹配集合中任意一个字符,注意逗号不是分隔符,[]不需要分隔符 4 print(re.findall("ab\df","ab5f")) #数字[0 - 9] 5 print(re.findall("ab\Df","ab5f")) #非数字 结果为[] 6 print(re.findall("ab\wf","ab_f")) #数字、字母、下划线、中文 结果:['ab_f'] 7 print(re.findall("ab\Wf","ab$f")) #非\w也就是非(数字、字母、下划线、中文 ) 结果为:['ab$f'] 8 print(re.findall("ab\sf","ab f")) # 所有的空白字符包,括空格、制表符、换页符等等 结果为:['ab f'] 9 print(re.findall("ab\Sf","ab f")) # \S 非空白 结果为:[] 10 11 12 量词: 13 print(re.findall("abc*","abccc")) #['abccc'] 任意多次 >=0 贪婪匹配 14 print(re.findall("abc?","abccc")) #['abc'] 可有可无 0次或者1次 惰性匹配 15 print(re.findall("abc+","ab")) #至少1次 >=1 没有匹配不成功 16 print(re.findall("abc{3}","abcc")) #固定m次 不够匹配不成功,超过了m个剩下的字符不要 17 print(re.findall("abc{3,}","abccccc")) #至少m次 不够匹配不成功,超过了m个剩下的字符全要 18 print(re.findall("abc{3,5}","abccccccc")) #固定3-5次不够匹配不成功,超过3-5的字符不要 19 20 边界: 21 print(re.findall("^(.*?)c$","abccdsac")) #: 以某某结尾 22 print(re.findall("^a(.*?)$","abccdsac")) #: 以某某开头 23 24 分组:(ab) 25 贪婪模式: .* 26 非贪婪(惰性)模式: .*? 27 28 re.I : 忽略大小写 29 re.M :多行匹配 30 re.S :单行匹配 31 32 re.sub(正则表达式, 替换内容, 字符串)
二.Xpath
如何使用xpath?
1.下载:pip install lxml 2.导包:from lxml import etree 3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点 2.1 本地文件:tree = etree.parse(文件名) tree.xpath("xpath表达式") 2.2 网络数据:tree = etree.HTML(网页内容字符串) tree.xpath("xpath表达式")
xpath用法展示参考如下:
1.文档文件
1 # 文本: 2 doc=''' 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8" /> 6 <title>测试bs4</title> 7 </head> 8 <body> 9 <div> 10 <p>百里守约</p> 11 </div> 12 <div class="song"> 13 <p>李清照</p> 14 <p>王安石</p> 15 <p>苏轼</p> 16 <p>柳宗元</p> 17 <a href="http://www.song.com/" title="赵匡胤" target="_self"> 18 <span>this is span</span> 19 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> 20 <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a> 21 <img src="http://www.baidu.com/meinv.jpg" alt="" /> 22 </div> 23 <div class="tang"> 24 <ul> 25 <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> 26 <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> 27 <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> 28 <li><a href="http://www.sina.com" class="du">杜甫</a></li> 29 <li><a href="http://www.dudu.com" class="du">杜牧</a></li> 30 <li><b>杜小月</b></li> 31 <li><i>度蜜月</i></li> 32 <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> 33 </ul> 34 </div> 35 </body> 36 </html> 37 '''
2.xpath查询实例
1 from lxml import etree 2 etree.parse("github.html") #用于打开文件 parse 3 tree=etree.HTML(doc) #打开HTML文档 用.HTML即可 4 5 6 注意在使用xpath,方法是 // 代表打开的整个文档 /代表下一级 7 属性定位: 8 找到class属性值为song的div标签 9 ret = tree.xpath("//div[@class='song']") 10 11 层级&索引定位: 12 找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a的网址 13 ret = tree.xpath("//div[@class='tang']/ul/li[2]/a/@href") 14 print(ret) 15 16 17 逻辑运算: 18 #找到href属性值为空且class属性值为du的a标签 19 ret = tree.xpath('//a[@class="du" and @href=""]') 20 print(ret) 21 22 23 模糊匹配: 24 查找属性title包含ng的a标签的内容 25 ret = tree.xpath('//a[contains(@title,"ng")]/text()') #注意:在contains和starts-with 中@xx和格式是以逗号,分开的 26 print(ret) 27 查找属性title以qin开始的a标签的内容 28 ret=tree.xpath("//a[starts-with(@title,'qin')]/text()") 29 print(ret) 30 31 32 33 取文本: 34 # /表示获取某个标签下的文本内容 35 # //表示获取某个标签下的文本内容和所有子标签下的文本内容 36 37 ret = tree.xpath('div[@class="song"]/p[1]/text()') 38 ret = tree.xpath('div[@class="tang"]//text()') 39 40 取属性: 41 ret = tree.xpath('div[@class="tang"]//li[2]/a/@href')
三:Beautifulsoup(BS)
概念:简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:
'''
Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
'''
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4。
解析器:
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐安装。
下面具体介绍BS的语法以及相应操作:
1.使用流程
- 导包:from bs4 import BeautifulSoup - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容 (1)转化本地文件: - soup = BeautifulSoup(open('本地文件'), 'lxml') (2)转化网络文件: - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml') (3)打印soup对象显示内容为html文件中的内容
2.基本方法总结:
(1)根据标签名查找 - soup.a 只能找到第一个符合要求的标签 (2)获取属性 - soup.a.attrs 获取a所有的属性和属性值,返回一个字典 - soup.a.attrs['href'] 获取href属性 - soup.a['href'] 也可简写为这种形式 (3)获取内容 - soup.a.string - soup.a.text - soup.a.get_text() 【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容 (4)find:找到第一个符合要求的标签 - soup.find('a') 找到第一个符合要求的 - soup.find('a', title="xxx") - soup.find('a', alt="xxx") - soup.find('a', class_="xxx") - soup.find('a', id="xxx") (5)find_all:找到所有符合要求的标签 - soup.find_all('a') - soup.find_all(['a','b']) 找到所有的a和b标签 - soup.find_all('a', limit=2) 限制前两个 (6)根据选择器选择指定的内容 select:soup.select('#feng') - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器 - 层级选择器: div .dudu #lala .meme .xixi 下面好多级 div > p > a > .lala 只能是下面一级 【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
3.基本方法示例:
from bs4 import BeautifulSoup soup=BeautifulSoup(html_doc,"lxml") 查找第一个a标签对象 print(soup.a) print(type(soup.a)) # 查找到的标签类型为:<class 'bs4.element.Tag'> 是一个标签对象 ################################################## 一 Tag对象的操作 ################################################### ------------------->> 属性操作 print(soup.a.attrs) #返回一个字典 结果:{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'} print(soup.a.attrs["href"]) #结果为:http://example.com/elsie print(soup.a.attrs["class"]) #结果为:['sister'] print(soup.a.attrs.get("id")) #结果为:link1 建议取法: print(soup.a["href"]) # http://example.com/elsie ------------------->> 文本操作 print(soup.a.text) # Elsie print(soup.a.get_text()) # Elsie #text和get_text() 取得的结果是一样的.调用方式不一样而已 print(soup.a.string) # Elsie #注意:text和string正常情况下取得的结果是一样,但取得的标签内含有多个标签取内容时:text全部取出 string不取 print(soup.p.text) # The Dormouse's story123 print(soup.p.string) # None
4.有关find_all和all,以及selector的具体使用
1 # 两个重要的搜索方法:find,find_all() 2 ################################################ 二 find,find_all()########################################### 3 4 5 #------------------------------>> 2.1 find_all() 6 # 1.取出文本中所有a标签,并循环打印连接和属性 7 # for link in soup.find_all("a"): 8 # print(link["href"],link['class']) 9 ''' 10 #结果为: 11 http://example.com/elsie ['sister'] 12 http://example.com/lacie ['sister'] 13 http://example.com/tillie ['sister'] 14 ''' 15 16 #相应参数: find_all(self, name=None, attrs={}, recursive=True, text=None,limit=None, **kwargs): 17 18 #------------------>> 2.1.1 name参数:name的五种过滤器: 字符串、正则表达式、列表、True、方法 19 #1.1、字符串:即标签名 20 # print(soup.find_all("a")) # name="a" 21 22 #1.2、正则表达式 23 # import re 24 # print(soup.find_all(re.compile('^p'))) #找出p开头的标签,结果有body和b标签 25 26 ''' 27 知识补充:re.compile()在正则表达式中的应用 28 cd = re.compile('abc{2}') 29 ret = re.findall(cd,"abccc") 30 print(ret) 31 32 ''' 33 34 #1.3、列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签: 35 # print(soup.find_all(["a","b"])) # name=["a","b"] 查找a标签和b标签 36 37 #1.4、True:可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点 38 # print(soup.find_all(True)) 39 # for tag in soup.find_all(True): 40 # print(tag.name) 41 42 #1.5、方法:如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False 43 # def has_class_but_no_id(tag): 44 # return tag.has_attr('class') and not tag.has_attr('id') 45 # print(soup.find_all(has_class_but_no_id)) 46 47 48 49 #------------------>> 2.1.2 属性参数 attrs={} 50 # print(soup.find_all("a",attrs={"class":"sister","id":"link2"})) 51 # print(soup.find_all("a",id="link2")) 52 # print(soup.find_all("a",class_="sister")) #因为class是关键字,需要查找的话在class加下划线,形式为:class_ 53 54 #------------------>> 2.1.3 文本参数 55 # print(soup.find_all("a",text="Elsie")) 56 57 #------------------>> 2.1.4 limit参数 58 # print(soup.find_all("a",limit=2)) #limit主要限制查找的条数 59 60 #------------------>> 2.1.5 recursive参数 61 #recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点, 62 # 如果只想搜索tag的直接子节点,可以使用参数 recursive=False . 63 64 # print(soup.find_all("div",recursive=False)) ##结果为[],因为第一层没有div 65 # print("----------------") 66 # print(soup.body.find_all("div",recursive=False)) #有结果 因为当前层为body 也就是说只找第一层,下面的层次不管有没有都不会去找了 67 68 # 局部查找 69 # print(soup.div.find_all(recursive=False)) ##只找div的子标签,子孙标签不管 70 71 72 ################################################ 2.2 find() 73 74 # print(soup.find("a")) # 等同于 soup.a 75 # find参数和find_all完全一样,但find只找一个标签 76 77 ################################################ 三 selector ################################################## 78 79 # 这个selector等同于css选择器 80 81 # print(soup.select(".sister")) 82 # print(soup.select("#link2")) 83 # print(soup.select(".c1 a"))
详细请参考:https://www.cnblogs.com/pyedu/p/10303283.html