三种爬虫的解析方式(re/bs/etr) 及 xpath的地址、/text()文本、string(.)批量输出等相关问题

‘’’

1、xpath爬取地址问题:

注意’/’、’//‘和’*’、’.‘和’[]’、’@'等谨慎对待地址,否则容易传入错误地址,使用xpath helper工具。

2、循环输出问题:

注意先大后小原则、注意是否使用text()获取文本内容 、 注意[0]来将地址获取的列表内容提取出来即转换str 、 注意str的清洗strip()及replace(,)等。

3、string(.)多文本批量输出、嵌套标签;starts-with相同字符开头属性的标签问题

嵌套标签’string(./)'地址获取多文本 及 相同字符开头的多个标签获取用 [starts-with(@,’***’)]来替代[@正常备注]的模式。

4、xpath爬取到空列表后遇到输出出现error显示超出索引的问题仍未攻克。

此坑未填,待攻克。《从零xpath爬取糗事百科内容》
后通过path地址重构,成功攻克输出列表为空及索引问题
代码如下:


import requests
from bs4 import BeautifulSoup
from lxml import etree

headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'}

url='https://www.qiushibaike.com/tesxt/'

res=requests.get(url,headers=headers)    #.content属性为二进制内容,另外还有.text的文本属性,set()方法可以添加属性及值
etr=etree.HTML(res.content)     #.HTML()方法解析方式可补全标签。另外.parse()可直接解析

#print(etree.tostring(etr))    #etree.tostring()方法将参数内元素序列化为XML树结构的编码字符串形式
print(type(etr))

#//*[@class="article block untagged mb15"]  #大循环
#//*/div[1]/a[2]  #ID小循环

infos=etr.xpath('//div[@class="article block untagged mb15"]')
print(type(infos))
print(len(infos))

content_list=[]
for info in infos:
    '''#注意XPath地址是  div[1]/a[2]/h2  ,而非 //*/div[1]/a[2]/h2/text()'''
    '''id=info.xpath('./div[1]/a[2]/h2/text()'''
    '''#为什么索引的时候会显示超出索引值,大概率是因为有 空列表的现象。?后通过xpath地址重构解决问题'''
    id=info.xpath('./div[1]//img/@alt')[0]  #注意变通xpath地址问题
    content=info.xpath('string(./a[1]/div/span)')  #注意使用string(.//)来批量爬去嵌套标签文本
    laugh=info.xpath('./div/span[1]/i/text()')[0]  #注意有时同一个元素的xpath地址也有可能不能
    comment=info.xpath('.//a/i[@class="number"]/text()')[0]  
    
    #print(id)    
    #print(content)
    #print(laugh)
    #print(comment)
    data={'id':id,
          'content':content,
          'laugh':laugh,
          'comment':comment}
    print(data)
 
    
#print(len(content_list))
#print(id)



填起来坑才走的动路,填上坑,走起路。开始填坑…
以下封装函数爬取酷狗音乐内容:

import requests
from bs4 import BeautifulSoup
from lxml import etree

headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'}

def get_kugou_etr(url):

    res=requests.get(url,headers=headers)
    etr=etree.HTML(res.content)      #.HTML()方法解析可自动补全标签,另外还有.parse()方法可直接解析
    #print(etree.tostring(etr))      #.tostring()方法将参数内元素序列化为XML树的编码字符串表示形式
    #print(type(etr))

    '''先大提取xpath形成list'''
    #//*[@id="rankWrap"]/div[2]/ul/li  #大循环
    infos=etr.xpath('//*[@id="rankWrap"]/div[2]/ul/li')
    #print(type(infos))
    #print(len(infos))
    '''后小循环提取xpath的大list转str'''
    for info in infos:
        '''#前三个序号的地址用'./*/text()'没有显示,需攻克,后改用'string(./)'成功攻克。'''
        #//*[@id="rankWrap"]/div[2]/ul/li/span[3]  #编号小循环 (前三个序号地址)
        #//*[@id="rankWrap"]/div[2]/ul/li/span[3]/strong  #除去前三个序号地址后的序号地址
        xuhao=info.xpath('string(./span[3])').strip()
        
        '''#注意不带/text()的文本,因为取得属性,直接得到属性值'''
        #//*[@id="rankWrap"]/div[2]/ul/li/@title  #歌手歌曲小循环
        geshougequ=info.xpath('./@title')[0]
        
        '''#注意这里要带上/text()取文本信息,因为span是元素名称,需要进行/text()来操作取得文本信息。'''
        #//*[@id="rankWrap"]/div[2]/ul/li/span[4]/span/text()  #时间小循环
        gequshijian=info.xpath('./span[4]/span/text()')[0].strip() 
    
        '''###########################仍需攻克######################
        #糗事百科为什么索引的时候会显示超出索引值,大概率就是因为有 空列表的现象。?'''
        data={'序号':xuhao,
              '歌手歌曲':geshougequ,
              '歌曲时间':gequshijian}
    
        #print(bianhao)
        #print(geshougequ)    
        #print(shijian)
        print(data)
    
    
if __name__=='__main__':
    urls=['http://www.kugou.com/yy/rank/home/{}-8888.html'.format(str(i)) for i in range(1,2)]
    for url in urls:
        get_kugou_etr(url)
    

巩固提升。《从零re、soup、etr性能对比来爬取糗事百科内容》
以下封装函数分别for循环个性比较三种爬取解析方式的性能
代码如下:


import requests
import re
from bs4 import BeautifulSoup
from lxml import etree
import time

headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'}


def re_scraper(url):
    res=requests.get(url,headers=headers)
    ids=re.findall('<h2>(.*?)</h2>',res.text,re.S)
    contents=re.findall('<div class="content">.*?<span>(.*?)</span>',res.text,re.S)
    laughs=re.findall('<span class="stats-vote"><i class="number">(.*?)</i>.*?</span>',res.text,re.S)
    comments=re.findall('<i class="number">(.*?)</i> ',res.text,re.S)
    for id,content,laugh,comment in zip(ids,contents,laughs,comments):
        info={'id':id,
              'content':content,
              'laugh':laugh,
              'comment':comment}
        #print(info)
        return info
        

def bs_scraper(url):
    res=requests.get(url,headers=headers)
    soup=BeautifulSoup(res.text,'lxml')
    ids=soup.select('div.author.clearfix > a > h2')  #获取单个属性时候不能使用 nth-child 改为 nth-of-type 
    contents=soup.select('a.contentHerf > div > span')
    laughs=soup.select('div > span > i')
    comments=soup.select('i.number')
    for id,content,laugh,comment in zip(ids,contents,laughs,comments):
        info={'id':id.get_text(),
              'content':content.get_text(),
              'laugh':laugh.get_text(),
              'comment':comment.get_text()}
        #print(info)
        return info
        


def etr_scraper(url):
    res=requests.get(url,headers=headers)
    etr=etree.HTML(res.text)    
    infos=etr.xpath('//*[@class="article block untagged mb15"]')
    for info in infos:
        id=info.xpath('./div[1]//img/@alt')[0]
        content=info.xpath('string(./a[1]/div/span)')  #注意用string(.//)的xpath地址来批量爬去嵌套标签文本。
        laugh=info.xpath('./div/span[1]/i/text()')[0]  #注意分析xpath的地址问题,有时相同元素地址也有不同。
        comment=info.xpath('.//a/i[@class="number"]/text()')[0]
        
        info={'id':id,
              'content':content,
              'laugh':laugh,
              'comment':comment}
        #print(info)
        return info



if __name__=='__main__':
    urls=['https://www.qiushibaike.com/tesxt/page/{}'.format(str(i)) for i in range(1,2)]
    
    for name,scraper in [('re爬虫',re_scraper),('bs爬虫',bs_scraper),('etr爬虫',etr_scraper)]:
        start=time.time()
        for url in urls:
            scraper(url)
        end=time.time()

        print(name,'用时:',end-start)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值