‘’’
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)