学习笔记
如果在本Blog里看到拼音,那可能是由于第一次shen he没通过被逼的,葛优躺,不知所措。
用Xpath匹配带来的数据合并问题
在我以往的爬虫案例中(比如:X凰X闻案例),我用Xpath分别得到了Xin闻名称列表name_list和Xin闻详情链接列表link_list,并用zip()函数,形成一个生成器对象,将两个列表’合在一起’。
部分代码如下(html源代码就不贴在这里了,太占位置了):
parse_html = etree.HTML(html)link_xpath = \
'//ul[@class="news-stream-basic-news-list"]/li[@class="news-stream-newsStream-news-item-has-image clearfix news_item"]//h2/a/@href'
name_xpath = \
'//ul[@class="news-stream-basic-news-list"]/li[@class="news-stream-newsStream-news-item-has-image clearfix news_item"]//h2/a/text()'
link_list = parse_html.xpath(link_xpath)
link_list = ['http:{}'.format(i) for i in link_list]
name_list = parse_html.xpath(name_xpath)
#只要使用xpath方法进行数据爬取,结果就会返回一个列表
data_zip = zip(name_list, link_list)
for item in data_zip:
print(item)
这种方法看起来很方便,但是利用内置生成器函数zip(),会产生一些严重的问题,进而导致后续的数据分析错误。
- 举个例子
有如下HTML代码:
<ol><li class="Ra01">
<name class = 'Bunny01'>小黄</name>
<age>8</age>
<food>胡萝卜</food>
</li>
<li class="Ra01">
<name class = 'Bunny02'>大白</name>
<age></age>
<food>白菜</food>
</li>
<li class="Ra02">
<name class = 'Bunny03'>奥尼尔</name>
<age>20</age>
<food>提草</food>
</li>
<li class="Ra03">
<name class = 'Bunny03'>王子</name>
<age>30</age>
<food>进口提草</food>
</li>
</ol>
可以看到这个HTML页面中有4对name和age数据,但是由于某些不明原因,导致某些age节点中的数据丢失。
如果此时,我们要获取HTML页面中name节点和age节点中的文本中,则它们的Xpath可以写成:
#name节点内文本//ol/li/name/text()
#age节点内文本
//ol/li/age/text()
此时我们编写python代码:
# -*- coding: utf-8 -*-from lxml import etree
html = \
"""
<ol>
<li class="Ra01">
<name class = 'Bunny01'>小黄</name>
<age>8</age>
<food>胡萝卜</food>
</li>
<li class="Ra01">
<name class = 'Bunny02'>大白</name>
<age></age>
<food>白菜</food>
</li>
<li class="Ra02">
<name class = 'Bunny03'>奥尼尔</name>
<age>20</age>
<food>提草</food>
</li>
<li class="Ra03">
<name class = 'Bunny03'>王子</name>
<age>30</age>
<food>进口提草</food>
</li>
</ol>
"""
parse_html = etree.HTML(html)
#获取所有name节点内文本
name_list = parse_html.xpath('//ol/li/name/text()')
print(name_list)
print('-'*20)
#获取所有age节点内文本
age_list = parse_html.xpath('//ol/li/age/text()')
print(age_list)
控制台输出:
['小黄', '大白', '奥尼尔', '王子']--------------------
['8', '20', '30']
我们看到,由于HTML源代码中某些age节点内的数据丢失,导致name_list和age_list的长度不一致,所以此时如果我们用内置生成器zip(),不仅会导致数据丢失,而且会导致name和age不匹配,这么说可能不够形象,我们zip()一下,试试:
for item in zip(name_list, age_list):print(item)
控制台输出:
('小黄', '8')('大白', '20')
('奥尼尔', '30')
我们看到,结果只输出了3条数据,且从’大白开始,各个name和age不匹配。
根据HTML源代码,我们得到的数据应该是这样的:
('小黄', '8')('大白', '')
('奥尼尔', '20')
('王子', '30')
所以,我们要换一种思维,用另一种方法,将数据’拼接’在一起。
比如:先获取每一个li节点对象,将这些对象装在一个列表中,再遍历这个列表中的li节点对象,并分别对各个li节点对象获取name和age文本数据,并将它们拼接在一起。同样,我们用代码演示一遍:
parse_html = etree.HTML(html)#获取所有li节点(大节点)对象
li_list = parse_html.xpath('//ol/li')
#print(name_list)
#print('-'*20)
data_list = []
#遍历li节点对象列表
for item in li_list:
name = item.xpath('./name/text()')
age = item.xpath('./age/text()')
if not name:
name = 'None'
if not age:
age = '0'
data_list.append((name[0], age[0]))
for item in data_list:
print(item)
注意,我们看到上面Xpath代码./name/text()中,最开头有一个.点,这个点有当前路径的意思,换句话说,这个点代表了li节点所在的位置。
控制台输出:
('小黄', '8')('大白', '0')
('奥尼尔', '20')
('王子', '30')
可喜可贺!得到的name和age数据一个不少,且没有出现name和age匹配错误的现象。