python爬虫之处理资源----xpath(lxml),beautifulsoup(bs4),正则表达式(re)

首先是lxml库:

#我用的火狐,安装一个try xpath插件就好了
"""
xpath路径:
1.选取节点:
    首先,随便一个节点名称,这是基本
    然后,单斜杠,/,如果出现在开头,那就从根节点寻找;
                           如果在某个节点后面,那就表示在该路径下的直接子节点
    还有,双斜杠,//,找去所有可以匹配的节点,不论路径.
    最后,@,根据属性查找节点/查找属性,如//div[@id]
2.谓语:
    用来查找某个节点或者某个包含特定值的节点,被嵌在方括号中
    方括号中的类似下标
    bookstore/book[1]:bookstore下的第一个book元素,
    还有last(),position()函数可供使用.
    book[@price]:所有有price属性的bookyuansu,
    book[@price>10]:所有price大于10的book元素.
    book[@price,"10"]:模糊匹配
3.通配符:
    /*某节点下的所有子节点
    book[@*]:所有带有属性的book节点
4.多个路径:
    使用"|"就好
5.运算符
"""

"""
lxml库,
是个高效的xml/html解析器."""

"""以下操作和html相关"""
#1,解析html代码:
from lxml import etree
import requests as re

#先准备一个html代码文件
respond=re.get("https://www.xsbiquge.com/79_79339/")
respond.encoding=respond.apparent_encoding
#核心方法1
htmlElement=etree.HTML(respond.text)

#转换字符串的方法:
print(etree.tostring(htmlElement,encoding="utf-8").decode("utf-8"))

#直接把文件转成html_Elemrent
#htmlElement=etree.parse("试一试.html")
#该方法还可以指定解析器:
HtmlParser=etree.HTMLParser(encoding="utf-8")
htmlElement=etree.parse("试一试.html",parser=HtmlParser)
#通过指定解析器,可以处理不规范的html文件(默认解析器是xml解析器)
#但在源代码为字符串的时候,从方法名称就可以看出它本来用的就是html解析器

print("----------------------------------------------------------------")
'''以下操作和xml,xpath相关'''
html=etree.HTML(respond.text)
#获取所有的div标签:
divs=html.xpath("//div")#该方法的返回值都是列表
for div in divs:
    print(etree.tostring(div,encoding="utf-8").decode("utf-8"))
#获取第二个div标签:
print("---------------")
div2=html.xpath("//div[2]")
print(etree.tostring(div2[0],encoding="utf-8").decode("utf-8"))
#获取class为"footer_link"的div标签
print("---------------")
divs=html.xpath("//div[@class='footer_link']")#该方法的返回值都是列表
for div in divs:
    print(etree.tostring(div,encoding="utf-8").decode("utf-8"))
#获取所有a标签的href属性:
print("---------------")
    #但是这里只获得了web项目目录后面的路径,
    #不是完整路径
hrefs=html.xpath("//a/@href")
for href in hrefs:
    print(href)
#获取该小说的所有章节名称:
print("---------------")
#出现了鬼畜,数字下标不能用,
#本来我打算一层层的div加上id或者class检索下来
#发现太麻烦,直接看id是"list"的div就好
xpathstring="//div[@id='list']/dl/*"
namesdd=html.xpath(xpathstring)
for name in namesdd:
    #第一种方法
    namea=name.xpath(".//a")
    #这是个双重获取,所以路径的写法要注意,"."表示相对路径
    for a in namea:
       print(a.text)
    #或者
    namea = name.xpath("a/text()")
    for a in namea:
        print(a)
#最简方法(对双斜杠的灵活使用):
xpathstring="//div[@id='list']//text()"
namesdd=html.xpath(xpathstring)
for name in namesdd:
    print(name)

然后还有bs4库:

from bs4 import BeautifulSoup
#beautifulsoup库,功能和lxml一样,也是用来解析html/xml/....的,
#正则表达式也是做这个的,它们三个相比,lxml最均衡,难度和速度都是中等,
#正则表达式速度最快,但是难度最大,beautiful速度最慢,但是最简单.

#先准备好html字符串:
import requests as re
respond=re.get("https://www.xsbiquge.com/79_79339/")
respond.encoding=respond.apparent_encoding
html=respond.text

#第一步:
bs=BeautifulSoup(html,"lxml")
#这里注意第二个参数,解析器,
#解析器有很多种:lxml,html.parser,html5lib--最好的容错性(速度慢),xml
#一般用lxml,遇见奇葩网站用htnl5lib


#有个pretty()方法,可以规整字符串
print("**************************************************")
#print(bs.prettify())



#具体的数据提取:

    #1.获取所有的a标签:
aes=bs.find_all("a")#find方法返回满足条件的第一个
for a in aes:
    print(a)

    #2.获取第二个a 标签:
aes=bs.find_all("a",limit=2)#limit参数是说最多提取几个参数
print(aes[1])#只能通过列表操作,没有xml快

    #3.获取class为"box_con"的idv(双条件获取同理)
        #方法1
divs=bs.find_all("div",class_="box_con")
for div in divs:
    print(div)
        #方法2:
divs=bs.find_all("div",attrs={"class":"box_con"})
for div in divs:
    print(div)

    #4.获取所有a标签的href属性:
aes=bs.find_all("a")
for a in aes:
        #4.1通过下标的方法
    href=a["href"]
    print(href)
        #4.2.通过attrs的属性获取:
    href=a.attrs["href"]
    print(href)

    #5.获取所有章节名(多层获取+获取字符串):
list_div=bs.find_all("div",id="list")[0]
aes=list_div.find_all("a")
for a in aes:
    print(a.string)#除了string属性,华友strings 和stripped_strings属性,获取所有(非空格)字符串
                          #如果标签下有多个内容(如换行符),string就无法获取了,用content


#CSS选择器:
#有标签--直接写,类名--加.,id--加#.,子孙元素--有空格(直接子元素有>),属性--中括号
#接下来我们用css选择器的方式将上述的需求再写一遍:
  #1.获取所有的a标签:
aes=bs.select("a")
for a in aes:
    print(a)

    #2.获取第二个a 标签:
aes=bs.select("a")
print(aes[1])

    #3.获取class为"box_con"的idv(双条件无法实现)
        #方法1
divs=bs.select("div.box_con")
for div in divs:
    print(div)
        #方法2:
divs=bs.select("div[class='box_con']")
for div in divs:
    print(div)

    #4.获取所有a标签的href属性(这个需求主要不是靠css实现的):
aes=bs.select("a")
for a in aes:
    href=a["href"]
    print(href)

最后是正则表达式相关:

#这个东西真是用的广:
import re

#最基本的匹配字符串:
text="hednniedjendjhelloncjdncj:mme"
pattern="he"
    #match()函数只能匹配开头
result=re.match(pattern=pattern,string=text)
print(result.group())

#2    "."     :匹配任意字符(除了换行符,只能匹配一个):
text="hednniedjendjhelloncjdncj:mme"
pattern="..."
result=re.match(pattern=pattern,string=text)
print(result.group())

#3     "\d"     匹配任意数字:
#4      "\D"    匹配任意非数字
#5       "\s"     匹配空白字符串(\n  \r   \t  还有空格)
#6     "\w"       匹配所有a-z,A-Z,0-9,还有_,就是可以在变量名可以出现的字符.
#7       "\W"     和"\w"匹配的相反

#8       "[]"            只要符合中括号中的字符,就可以匹配
    #[0-9]  = \d
    #[0-9 a-z A-Z _]  = \w
    #8.1      可见 '-' 也是个特殊字符
    #8.2        "^"在中括号种就是取反
#9        'X+'           符合X条件的一个或多个
#10         "X*"        符合X条件的零到多个
#11         "^X"       匹配不符合X的字符
#12         "?"         匹配一个或者零个
#13         "{m}"     匹配m个
#14         "{m,n}"     匹配m-n个
#15         "^X"          检查整个字符串以X开头
#16          "X$"          检查整个字符串是否以X结尾,X必须是非规则表达式(正常字符串)
# 17          "|"            取或

#贪婪模式(匹配尽量多的字符,默认)和非贪婪模式(匹配尽量少的字符,加在+*等后面)
#注意原生字符串和转义字符串,要匹配的字符串里有两个//表示/,你要匹配/,正则表达式要写//,加上转移,就得写,所以给正则表达式加个r表示原生字符串就完事了.

#分组,group:
text="abaabaaabaaab"
pattern="(a+b)(a+b)(a+b)"
result=re.search(pattern=pattern,string=text)
print(result.groups())
#分组对应正则表达式中的括号的分组,第一个括号中的内容就是group(1),
#以此类推,整个正则表达式就是group(0)
#groups可以将所有的括号对应的组拿出来,并去掉group(0)

#find_all:
text="abaabaaabaaab"
pattern="(a+b)"
#返回所有可以和正则表达式匹配的字符串
result=re.findall(pattern=pattern,string=text)
print(result)

#sub() 替换:
text="abaabaaabaaab"
pattern="(a+b)"
result=re.sub(pattern=pattern,repl="找到了",string=text)
print(result)
#可以re.sub("<.+?>",repl="",string=html):可以去掉html中的所有标签<>

#split()函数:
text="ab    aab   aaab  aaab"
pattern=" +"
result=re.split(pattern=pattern,string=text)
print(result)

#compile(),两个功能:
#1.一个正则表达式经过多次使用,可以先把这个正则表达式编译成对象,每次传这个对象
#2.设置为re.VERBOSE: 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释

text="abaabaaabaaab"
regex=re.compile("""
a#就是字母a
#是指a的个数
b#是指字母b
""",re.VERBOSE)
#re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
result=re.search(regex,string=text)
print(result.groups())

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值