爬虫(第二部分)
爬虫总结02(爬虫解析器:正则,xpath,BS)
一:常用正则表达式解析
单字符: . : 除换行以外所有字符 [] :[aoe] [a-w] 匹配集合中任意一个字符 \d :数字 [0-9] \D : 非数字 \w :数字、字母、下划线、中文 \W : 非\w \s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 \S : 非空白 数量修饰: * : 任意多次 >=0 + : 至少1次 >=1 ? : 可有可无 0次或者1次 {m} :固定m次 hello{3,} {m,} :至少m次 {m,n} :m-n次 边界: $ : 以某某结尾 ^ : 以某某开头 分组: (ab) 贪婪模式: .* 非贪婪(惰性)模式: .*? re.I : 忽略大小写 re.M :多行匹配 re.S :单行匹配 re.sub(正则表达式, 替换内容, 字符串)
二:xpath解析
01:测试html数据:
<html lang="en"> <head> <meta charset="UTF-8" /> <title>测试bs4</title> </head> <body> <div> <p>百里守约</p> </div> <div class="song"> <p>李清照</p> <p>王安石</p> <p>苏轼</p> <p>柳宗元</p> <a href="http://www.song.com/" title="赵匡胤" target="_self"> <span>this is span</span> 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a> <img src="http://www.baidu.com/meinv.jpg" alt="" /> </div> <div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a href="http://www.sina.com" class="du">杜甫</a></li> <li><a href="http://www.dudu.com" class="du">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div> </body> </html>
02:常用xpath表达式及符号说明:‘/’ 取文本
属性定位: #找到class属性值为song的div标签 //div[@class="song"] 层级&索引定位: #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a //div[@class="tang"]/ul/li[2]/a 逻辑运算: #找到href属性值为空且class属性值为du的a标签 //a[@href="" and @class="du"] 模糊匹配: //div[contains(@class, "ng")] //div[starts-with(@class, "ta")] 取文本: # /表示获取某个标签下的文本内容 # //表示获取某个标签下的文本内容和所有子标签下的文本内容 //div[@class="song"]/p[1]/text() //div[@class="tang"]//text() 取属性: //div[@class="tang"]//li[2]/a/@href
03:基本操作:
#第一部导安装模块 pip3 install lxml #第二步:测试前先倒入模块 from lxml import etree 使用的基本原理:将html文件文档转换成一个etree 对象,然后调用这个对象指定的方法来查找指定的节点 方法一: tree=etree.HTML(doc) #用网络数据转换成对象 方法02:用读取本地文件转换成对象 tree=etree.parse("test.html") print(">>",tree) # <lxml.etree._ElementTree object at 0x0000002F7C68E708>
操作例子:
001: ret=tree.xpath("//a[@id='feng']/text()") print(ret) # ['凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘'] 002: ret=tree.xpath("//a[@id='feng']/@href") a标签下 id值为feng下的链接--> ['http://www.haha.com'] 003: ret=tree.xpath("//div[@class='tang']/ul/li/a/@href") ['http://www.baidu.com', 'http://www.163.com', 'http://www.126.com', 'http://www.sina.com', 'http://www.dudu.com', 'http://www.haha.com'] 004: ret=tree.xpath("//div[@class='tang']/ul/li/b/text()") # ['杜小月'] ret=tree.xpath("//a[@class='du' and @href='']/text()") #['总为浮云能蔽日,长安不见使人愁'] 005: ret=tree.xpath("//a[@title='qin']/text()") ['秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山'] 006: ret=tree.xpath("//a[starts-with(@title,'qin')]/text()") ['清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村', '秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山'] print(ret)
三:BS解析(Beautiful Soup)
ps: Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过 你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.
Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,
官网推荐在现在的项目中使用Beautiful Soup 4
01:安装BS
pip3 install beautifusoup4
02:解析器
001:Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器, lxml 解析器更加强大,速度更快,推荐安装。 002:另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib: pip3 install html5lib
03:BS的使用方法:
001:使用方法: a:导包:from bs4 import BeautifulSoup b:可以将一个本地的html文档或者网络的文件转换成一个BeautifuSoup对象,通过操作对象的属性方法来查找指定的节点内容 --soup=BeautifulSoup(open("test.html(本地文件)","lxml")) 或者soup=BeautifulSoup("doc(网络数据)","lxml") 002:打印soup对象内容为html文件中的内容
04:BS的基本语法
soup=BeautifulSoup(open("test.html)(本地文件)","lxml") (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选择器返回永远是列表,需要通过下标提取指定的对象
五:BS解析的语法案例操作
案例源码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="c1"> <!--<p>123</p>--> <!--<p>345</p>--> <div> </div> </div> <div> <p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b><span>123</span></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> </div> </body> </html> 案例代码
ps重点:soup.p.text和soup.p.string的区别: 例子:<p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b><span>123</span></p> print(soup.p.string) # None print(soup.p.text) # The Dormouse's story123 >>总结:string在一个标签里面再套上其他标签的时候,只会打印None,text不管一个标签里面套上多少个标签, 都会将这个标签里面所有的文本取出来
操作步骤:
第一步:先导包,实例化一个对象出来 from bs4 import BeautifulSoup 实例化对象的两种方法: 方法01:soup = BeautifulSoup(open("test00.html"), "lxml") 方法02:# soup = BeautifulSoup(html_doc, "lxml")
实际操作案例:
01:Tag对象的操作 001:查找第一个a标签 print(">>", soup.a) # <a>111</a> print(">>", soup.a.attrs) # {'class': ['a1']} 02:Tag对象的属性操作 001:soup.a标签的类型: print("type是>>", type(soup.a)) # <class 'bs4.element.Tag'> 002:Tag对象的属性操作 print(soup.a.attrs["href"]) # 这个标签对象的链接 http://example.com/elsie 003:Tag对象标签的class名 print(soup.a.attrs["class"]) # ['sister'] 004:找出这个标签的id名字 print(soup.a.attrs["id"]) # link1 总结:----〉标签对象的属性操作的简单写法 print(">>", soup.a["href"]) # http://example.com/elsie 03:Tag对象的文本操作 print(soup.a.text) # Elsie print(soup.a.get_text()) # Elsie 对象有get方法 print(soup.a.string) # Elsie # 04:对象的find()和find_all()操作(find和find_all的详解(两者的参数说明是一样的,这里只取了find_all()为例子)) 01:find_all() #找到文本中所有的 指定标签 001:4种name参数过滤器 第一种: 例子01: ls = soup.find_all("a") #name="a" print("ls>>", ls) #结果是一个列表,可以进行循环 第二种: 例子02: ls = soup.find_all(["a", "p"]) # 找出所有的a标签和p标签 name=["a","p"] print(">>>++", ls) # 结果是一个列表,可以进行循环 第三种: 例子03: import re print(">>>?",soup.find_all(re.compile("^b"))) #找出文本中所有以b开头的标签,body标签会被找出来,结果是一个列表 第四种: 例子04: def has_class_but_no_id(tag): return tag.has_attr('class') and not tag.has_attr('id') print("...",soup.find_all(has_class_but_no_id)) # name=has_class_but_no_id 002:attrs属性参数过滤器 print(soup.find_all("a", attrs={"class": "sister","id": "link1"}))#[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] 属性参数过滤简写: print(soup.find_all("a",id="link3")) #[<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] 003:text文本参数过滤 print(soup.find_all("a",text="Tillie")) #[<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] 004:limit参数 print(soup.find_all("a",limit=2)) #只找文本中的前2个a标签 005:recursive参数(递归) print("True>>",soup.find_all("a",recursive=True)) #recursive 深度可以一直找下去,直到找完文本中所有的a标签 print("False",soup.find_all("a",recursive=False)) # 深度为零 006:recursive深度产生局部查询 案例01:找第一个div标签内部所有的标签,recurs默认是True,所以会将recursive内部所有同级的标签以及同级标签的字标签全部找出来 print(soup.div.find_all()) 案例02:recursive设置为False,则找出第一个div标签内部所有的同级标签,同级标签的字标签不会被找出来 print("recursive>>>>",soup.div.find_all(recursive=False)) #找第一个div标签内部 04:selector操作 ps:selector的标签查找操作和css选择器一样
普通人!