基于Python的爬虫协议、parser解析及bs4案例(旧)

爬虫协议

爬虫协议:Robots协议(机器人协议),全名:网络爬虫排除标准。
            用来告诉搜索引擎,哪些页面可以抓取,哪些页面不可以抓取。
            该协议通常是一个robots文本文件。一般放在网站的根目录底下。
            当我们用爬虫搜索某一网站时,会先检查该网站点的根目录下是否存在爬虫协议。
            如果找到,则按照该协议进行爬取,如果没有,该网站点的所有内容都会被爬取。
1、百度的robot协议
            可以直接访问https://www.baidu.com/robots.txt
            robots.txt样例(百度):
            User-agent: Baiduspider     爬虫名称:允许Baiduspider去访问   *(任何爬虫都可以爬取)
            Disallow: /baidu            Disallow指定了不允许抓取的记录    /(根目录,都不允许抓取)
2、解析爬虫协议
'''解析爬虫协议
    该类根据网站的robots.txt文件来判断一个爬虫是否有权限
'''
from urllib.robotparser import RobotFileParser
rp = RobotFileParser("https://www.136book.com/robots.txt")
rp.read()   # read()方法用来读取读取robots.txt文件并分析,该方法不会返回任何内容。但是执行了读取操作。

'''判断某一网站是否能被读取'''
# can_fetch(self, useragent, url)
flag = rp.can_fetch('*', 'https://www.136book.com/anlianjushenghuainanquanji/qlrcxeqleb/')
print(flag) # True

urllib库中parse解析器

urllib库中提供了parse模块,提供了一个处理URL的标准接口,比如:实现URL各部分的抽取,合并以及链接转换
        urlparse(url,scheme,allow_fragments):可以实现url的识别和分段
        url:网址
        scheme:协议
        allow_fragments:允许锚点
1、解析网页

使用urllib.parse的urlparse模块,可以把网址解析,分割成不同部分。

from urllib.parse import urlparse
result = urlparse("http://www.baidu.com/index.html;user?id=5#comment")
# result = urlparse("http://www.baidu.com/index.html;user?id=5#comment",scheme='',allow_fragments=False)
print(type(result),result)
# <class 'urllib.parse.ParseResult'>
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
'''分析一下上面打印的内容
scheme:协议
netloc:域名
path:路径
params:参数
?后的query:查询条件(一般用于get类型的URL)
#后的是锚点:直接定位页面的下拉位置
公式:scheme://netloc/path;params?query#fragment
'''
result = urlparse('www.ZangYushun.com',scheme='https')
print(result)
# ParseResult(scheme='https', netloc='', path='www.ZangYushun.com', params='', query='', fragment='')

# allow_fragments是否允许锚点
result = urlparse("http://www.baidu.com/index.html;user?id=5#comment",scheme='',allow_fragments=False)
print(result.scheme,result[0],result.netloc,result[1],sep='\n')
2、反解析unparse()

urlunpaese():参数式一个可迭代对象,但是它的长度必须为6,否则会抛出异常

'''scheme, netloc, url, params, query, fragment'''
from urllib.parse import urlunparse
data = ['http','www.baidu.com','index.html','user','a=6','comment']
print(urlunparse(data)) # http://www.baidu.com/index.html;user?a=6#comment

from urllib.parse import urlsplit
# urlsplit()方法和urlparse方法类似,只不过不再单独解析params这一部分。只返回5个结果
result = urlsplit('http://www.baidu.com/index.html;user?a=6#comment')
print(result)   # SplitResult(scheme='http', netloc='www.baidu.com', pa

bs4.BeautifulSoup

和lxml一样,BeautifulSoup是一个HTML/XML解析器,主要的功能也是如何解析和提取HTML/XML中的数据
    lxml只会局部遍历,而Beautifulsoup是基于HTML DOM结构的,会载入整个文档,解析整个DOM树结构。
    因此,时间和内存开销都会比较大,所以性能要低于lxml

    BeautifulSoup用来解析HTML比较简单,API比较人性化,
    且支持CSS选择器,python标准库中的html解析器,也支持lxml的XML解析器
1、使用BeautifulSoup对网页进行解析
from bs4 import BeautifulSoup
html = '''
<html><head><title>The title</title></head>
<body>
<p class = "title" name="dromouse"><b>The Dormouse's story</b></p>
<p class = "story">
    <a href = "https://www.baidu.com" class = "sister" id = "link1">1<!--测试注释--></a>
    <a href = "https://www.baidu.com" class = "sister" id = "link2">2</a>
    <a href = "https://www.baidu.com" class = "sister" id = "link3">3</a>
ceshi2</p>
<p class = "story">...</p>
'''
# 创建Beautifulsoup对象
soup = BeautifulSoup(html,features='lxml')
# soup = BeautifulSoup(open('index.html'))

# 格式化输出soup对象的内容,补齐标签
print(soup.prettify())
print(soup.title)
print(soup.head)
print(soup.a)
print(type(soup.p))
print(soup.head.name)   # 对于其他内部标签,输出的值为标签本身的名字
print(soup.p.name)
'''上述代码打印内容:
	<title>The title</title>
	<head><title>The title</title></head>
	<a class="sister" href="https://www.baidu.com" id="link1">1<!--测试注释--></a>
	<class 'bs4.element.Tag'>
'''
# 以字典的形式吧p标签的所有属性打印输出
print(soup.p.attrs) # {'class': ['title'], 'name': 'dromouse'}
print(soup.p['class'])  # ['title']
print(soup.p.get('class'))  # ['title']
# 修改属性
soup.p['class']='newClass'
print(soup.p)  # <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>
# 删除属性
del soup.p['class']
print(soup.p)   #  <p name="dromouse"><b>The Dormouse's story</b></p>
# 输出标签包含的内容
print(soup.p.string)    # The Dormouse's story
print(type(soup.name))
print(soup.name)
print(soup.a.string)
2、bs4案例
BeautifulSoup 将复杂的HTML文档转换成复杂的树形结构,每个节点都是python对象。所有对象可以归纳为4种:
    1、Tag对象
    2、NavigableString
    3、BeautifulSoup
    4、Comment

    Tag: html中的标签,每个标签成称为tag对象。
        我们可以使用soup加上标签轻松的获取这些标签的内容,这些对象的类型是bs4.element.Tag'
        但是注意:它查找的是所有内容中的第一个符合要求的标签。。。。(不能查询所有的标签)

    BeautifulSoup:对象表示的是一个文档的内容,大部分时候,可以把他当做tag对象,是一个特殊的tag
    print(type(soup)) # unicode

    Comment对象是一个特殊的NavigableString对象,输出的内容不包括注释符号,如果包含注释,通过.string获取内容为None

——————————————————————————————————————————————————————————

遍历文档树:
    1、直接子节点:.contents   .children属性
        .contents属性 可以量tag的子节点以列表的方式输出/
        .children属性:返回的值不是一个list,通过遍历获取所有的子节点

搜索文档树:
    1、find_all(name, attrs, recursive, text, limit, **kwargs)
        name 参数:name参数可以查找所有名字为name的tag对象,字符串对象会被自动忽略掉
        列表参数:Beautifulsoup对象将会与列表中任一元素的匹配返回。

    2、select()通过css选择器进行查找
        ①通过标签名查找
        ②通过类名来查找
        ③通过id来查找
        ④组合查找: 和写class文件时,标签名与类型、id进行组合。
        ⑤属性查找: 查找可以添加属性元素,属性需要用中括号括起来,注意属性和标签属于同一结点。
               所以中间不能添加空格,否则无法匹配到
            print(soup.select('a[class="sister"]'))
        ⑥获取内容

案例验证上述方法:

from bs4 import BeautifulSoup
html = '''
<html><head><title>The title</title></head>
<body>
<p class = "title" name="dromouse"><b>The Dormouse's story</b></p>
<p class = "story">
    <a href = "https://www.baidu.com" class = "sister" id = "link1">1<!--测试注释--></a>
    <a href = "https://www.baidu.com" class = "sister" id = "link2">2</a>
    <a href = "https://www.baidu.com" class = "sister" id = "link3">3</a>
ceshi2</p>
<p class = "story">...</p>
'''
# 创建Beautifulsoup对象
soup = BeautifulSoup(html,features='lxml')
# print(soup.body.contents)
# print(soup.body.contents[1])
#
# soup.find_all()
#
# for child in soup.body.children:    # 打印了所有的p标记
#     print(child)
#
# text = soup.find_all('a')
# print(text)

text = soup.find_all(['a','b'])
text = soup.find_all(id = 'link2')
text = soup.find_all(text = '1')
text = soup.find_all(text = ['1','2','3'])
text = soup.select('title')
text = soup.select('.sister')
text = soup.select('#link1')
text = soup.select('p #link1')
text = soup.select('head > title')
text = soup.select('a[href="https://www.baidu.com"]')

# print(text.get_text())
print(soup.select('a[href="https://www.baidu.com"]'))
text = soup.select('a[href="https://www.baidu.com"]')[0].get_text()
print(text)

for title in soup.select('title'):
    print(title.get_text())

爬取双色球信息案例

打开网页:http://zst.aicai.com/ssq/openInfo
爬取最新的双色球信息2021-5-16:
双色球

1、使用select方法,爬取信息
'''爬取最新日期的双色球信息,并打印出红球和蓝球的号码'''
import requests
from bs4 import BeautifulSoup
# 爬取数据
def get_html(url, headers):
    request = requests.get(url,headers)
    try:
        if request.status_code == 200:
            print("获取成功,网页长度:", len(response.text))
            response.encoding = 'utf-8'
            return response.text
    except BaseException as e:
        print("抓取信息错误", e)
# 分析数据
def get_soup(html):
    soup = BeautifulSoup(html,'lxml')   # 可以解析xml和html
    # soup = BeautifulSoup(html,'html.parser')  # 可以解析html
    #date = soup.select('div.dataContent form div.mainTab.mainTab_lskj table tbody tr td')
    date = soup.select('tbody tr:nth-child(3) td:nth-child(2)')
    print(date)
    red = soup.select('tbody tr:nth-child(3) td.redColor')
    print(red)
    blue = soup.select('tbody tr:nth-child(3) td.blueColor')
    print(blue)
    print("最新日期",end=':')
    for i in range(len(date)):
        print(date[i].string,end=' ')
    print("红球号码",end=':')
    for i in range(len(red)):
        print(red[i].string,end=' ')
    print("蓝球号码",end=':')
    for i in range(len(blue)):
        print(blue[i].string,end=' ')
if __name__ == '__main__':
    url = 'http://zst.aicai.com/ssq/openInfo'
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
    response = requests.get(url,headers = headers)
    html = get_html(url,headers)
    get_soup(html)
2、使用find的方法爬取元素数据
import requests
from bs4 import BeautifulSoup
# 爬取数据
def get_html(url, headers):
    request = requests.get(url,headers)
    try:
        if request.status_code == 200:
            print("获取成功,网页长度:", len(response.text))
            response.encoding = 'utf-8'
            return response.text
    except BaseException as e:
        print("抓取信息错误", e)
# 分析数据
def get_soup(html):
    soup = BeautifulSoup(html,'lxml')   # 可以解析xml和html
    tr = soup.find('tr', attrs={'onmouseout':"this.style.background=''"})
    print(tr)
    tds = tr.find_all('td')
    print('最新日期:',tds[1].string)
    print('红球号码',end=':')
    for i in range(2,8):
        print(tds[i].string,end=' ')
    print('\n蓝球号码:',tds[8].string)
    # 最新日期: 2021 - 05 - 16
    # 红球号码: 07 10 14 16 24 33
    # 蓝球号码: 16

if __name__ == '__main__':
    url = 'http://zst.aicai.com/ssq/openInfo'
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
    response = requests.get(url,headers = headers)
    html = get_html(url,headers)
    get_soup(html)

爬取图片结合tkiner案例

爬取汽车排行前三的网页链接,再进入链接爬取图片,并且在tkiner中可以点击显示

网址:https://www.autohome.com.cn/channel2/bestauto/list.aspx?type=1
汽车排行
汽车图片

'''爬取汽车排行榜及其图片,在tinker中显示出来'''
import requests
from bs4 import BeautifulSoup
# 爬取数据
def get_html(url, headers):
    request = requests.get(url,headers)
    try:
        if request.status_code == 200:
            print("获取成功,网页长度:", len(response.text))
            # response.encoding = 'utf-8'
            return response.text
    except BaseException as e:
        print("抓取信息错误", e)
# 得到top3的链接
def get_soup_top(html):
    soup = BeautifulSoup(html,'lxml')   # 可以解析xml和html
    Alllist = soup.select("div.pc_rank table tr td.n2 p a")
    top = []
    top.append(Alllist[0]['href'])
    top.append(Alllist[1]['href'])
    top.append(Alllist[2]['href'])
    return top
# 访问top3的链接,并且爬取图片的路径
def get_top_pic(top,headers):
    pics = []
    for i in range(len(top)):
        if "http" not in top[i]:
            top[i] = 'https:' + top[i]
        request = requests.get(top[i], headers)
        soup1 = BeautifulSoup(request.text, features='lxml')  # 可以解析xml和html
        pic = soup1.find('img', attrs={'width': '744'})
        if "http" not in pic:
            pics.append("https:" + pic['src'])
        else:
            pics.append(pic['src'])
    # print(top)
    print(pics)
    return pics

def save_pic(pics, headers):
    for i in range(len(pics)):
        path = "D://12119//pics//" + pics[i].split('/')[-1]
        r = requests.get(pics[i], headers=headers)
        with open(path, 'wb') as f:
            f.write(r.content)
            f.close()

def show_pic():
    import tkinter,os
    from PIL import Image, ImageTk
    # 创建一个窗体,top
    top = tkinter.Tk()
    top.geometry("500x309")
    text = tkinter.StringVar()
    path = 'D://12119//pics//'
    filelist = os.listdir(path)
    img_open = Image.open(path + filelist[0])
    img = ImageTk.PhotoImage(img_open)
    img_open2 = Image.open(path + filelist[1])
    img2 = ImageTk.PhotoImage(img_open2)
    img_open3 = Image.open(path + filelist[2])
    img3 = ImageTk.PhotoImage(img_open3)
    label_img = tkinter.Label(top, image=img)
    def one():
        label_img.configure(image = img)
    def two():
        label_img.configure(image = img2)
    def three():
        label_img.configure(image = img3)
    button1 = tkinter.Button(top, text="1", foreground='red',command = one,
                            activebackground='white', activeforeground='black').place(x=100,y=50)
    button2 = tkinter.Button(top, text="2", foreground='red',command = two,
                            activebackground='white', activeforeground='black').place(x=100,y=100)
    button3 = tkinter.Button(top, text="3", foreground='red',command = three,
                            activebackground='white', activeforeground='black').place(x=100,y=150)
    label_img.pack()

    top.mainloop()

if __name__ == '__main__':
    url = 'https://www.autohome.com.cn/channel2/bestauto/list.aspx?type=1'
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'}
    response = requests.get(url,headers = headers)
    html = get_html(url,headers)
    top = get_soup_top(html)
    pics = get_top_pic(top, headers)
    save_pic(pics, headers)
    show_pic()

显示效果:点击左侧按钮可以切换图片
car1
car2
car3


如果这篇文章对你有帮助的话,点个赞呗~

python根据需求完成一个TXT解析器的简单开发 一 修改说明: 需求一: 一开始说要解析UECapabilityInfo 消息里的supportedBandCombination-r10 这个IE里的CA组合转化成易阅读的表现形式. 我以为一组CA组合就是一组: bandEUTRA-r10 ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 功能实现: 有效信息筛选:于是就用循环把UECapabilityInformation的数据里每一行作为一个元素放到list里面 然后用bandEUTRA-r10作为一组CA的识别信息、在筛选出同组ca-BandwidthClassUL-r10、ca-BandwidthClassDL-r10、supportedMIMO-CapabilityDL-r10的信息,添加保存到字符串中,然后再把字符串作为元素添加到list中去。最后遍历list的元素写入目标文件 需求二: 然后收到反馈CA组合的理解是错误的。一组CA组合应该是以大括号作为识别的,里面可能包含多组: bandEUTRA-r10: ca-BandwidthClassUL-r10 ca-BandwidthClassDL-r10 supportedMIMO-CapabilityDL-r10 CA组合识别原理:在查看UECapabilityInformation内的CA组合后 发现CA组合内第一个 bandEUTRA-r10因为比其他bandEUTRA-r10多了一层的CA组合的大括号,所以如果给每一行增加索引的话就会发现除了第一个bandEUTRA-r10,其他bandEUTRA-r10到上一个supportedMIMO-CapabilityDL-r10的距离都是一样的,为了减少复杂度,我删除了所有’{’,这样所有除了所有CA组合第一个bandEUTRA-r10往上第四行是’}’其他bandEUTRA-r10的往上第四行都是supportedMIMO-CapabilityDL-r10 功能实现: 添加索引:便利时用了for enumerate()循环,这样便利时可以在循环时,自动为每个元素生成索引 CA组合识别:在识别到bandEUTRA-r10时,增加一个判断if datalist1[index-4].startswith(),如果bandEUTRA-r10的往上第四行是supportedMIMO-CapabilityDL-r10说明同组CA未结束,把筛选的有效信息强制类型转换后添加在上个元素末尾,反之则说明是个新的CA组合,往列表里添加一个新的元素。 需求三: 之后收到反馈CA组合虽然识别了,但是排序不行,需要按照CA组合支持的band进行排序 功能实现: 排序:于是我在识别完CA组合后,增加了一个循环和count(),用CA组合里的’-’给它们归类 比如1AA,11A,21AA是一类;1A-1A,2A-1AA,3A-1A是一类 在用一个中间变量保存开头的band的数字,一个类中把开头支持band的数字字母相同的CA组合归为一行 比如1A-21A,1A-22A一类1AA-2AA 1AA-3AA为一类 需求四: 之后收到反馈,CA组合分类不能只按照开头比较分类,不然一但数据多了会对查阅带来极大不便,应该按照每组CA组合中bandEUTRA-r10的值进行判断,比如1AA-2AA,1A-2AA和1AA-2A应该归在同一行 实现原理:首先我想的是按位比较数字,但是因为字母的数量不稳定,数字的位置不一定对应,然后我就想把数字全部提取出来作为索引,在相应的索引后面添加同组元素,用dict来实现排序。难点就在于从字符串中提取数字。后来在python的正则表达式中找到相关的处理函数compile()(设置匹配对象类型)和findall()(找到所有匹配对象并以list返回)。 功能实现: 第二次排序:在上次的排序中我保留了分类和从小到大的排序。方便提取索引时,索引也是从小到大。每遍历一个元素(CA组合有效信息),就compile()和findall(),从该元素中提取数字组合(在compile()的参数中添加()就能够使提取的内容成为一组数据),然后通过dict自带函数setdefault()添加索引,并可以设置索引值为list类型(dict类型的索引的值不可变,但如果类型为list,list的内容可以进行改动),避免重复索引,在本次遍历中完成将元素添加到索引值对应的list中去 需求五: 之后对程序进行测试,在测试test2时发现layers增加了fourlayers类型后,用来代表layers的数字2和4会影响分类结果。比如1AA(2)-1AA(2)和1A(4)-1A(2)会被归为两类。 test1:当CA组合的格式为xx-xx-xx-xx-xx(最长可识别为五位元素的组合,再长就需要修改代码) test2:当CA组合包含fourLayers test3:当CA组合缺失某种格式比如xx-xx时发现layers增加了fourlayers 功能实现: : 解除layers对排序的影响:用II 和 IV替代2,4来表示layers,测试后不影响阅读与分类 二、整体程序架构: 1.通过循环和自带的startswith()先将每组CA组合的有效信息识别 2.通过sorted()函数将所有CA组合从小到大排列 3.通过count()函数将所有CA组合根据格式不同分类 4.通过循环和正则表达式的split()对所有CAlist数据进行处理(用split处理只是防止出现不必要的错误) 5.通过循环和正则表达式compile()和findall()识别所有CA组合中数字,并将同一组合中的数字合为一个元素(在同一循环,用这个数字的元素作为一个dict的索引),用dict自带的setdefault()进行Key的添加顺便设置Key的值为list,避免Key重复,在用append把当前Key的字符串,添加到Key对应值的list中去 6.最后对dict整体遍历,将每一个Key的值输出到文本中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值