python爬虫网页解析器怎么写_python爬虫系列之 html页面解析:如何写 xpath路径

一、前言

上一节我们讲了怎么批量下载壁纸,虽然爬虫的代码很简单,但是却有一个很重要的问题,那就是 xpath路径应该怎么写。

这个问题往往会被我们忽略,但 xpath路径的写法是很重要的。不同的 xpath路径写法会后续爬取代码会产生很大影响,而且不同的 xpath写法的稳定性也不同,能不能写出优雅稳定的代码就要看 xpath写得好不好了。

下面我们来讲讲为什么 xpath的写法这么重要

二、为什么 xpath写法很重要

我们拿几个例子来讲讲不同 xpath写法对代码的影响,以我的个人主页作为解析对象:

现在的需求是要爬取我个人主页里的文章列表,包括文章的链接、标题、访问量、评论数和点赞数量

ff37a8524e72

个人主页

爬之前我们先分析一下

1、爬什么:文章链接文章的链接、标题、评论数和点赞数量

2、怎么爬:requests请求网页、xpath解析网页

接下来正式开始爬取:

第一步:分析网页,写出图片的 xpath路径

第二步:用 requests库获取网页

第三步:使用 lxml库解析网页

第四步:把爬取到的信息保存下来

我们一步一步来,首先分析网页,写出 xpath

按 F12进入开发者模式,找到文章列表所在的标签

ff37a8524e72

example-2.png

可以看到,文章列表是一个 ul标签,ul标签下的每一个 li标签分别代表一篇文章。

我们要爬的信息都在 class="content"的 div标签下:

文章链接是第一个 a标签的 herf属性值

文章标题是第一个 a标签的文本属性的值

文章的评论数是 class="meta"的 div标签下的第二个 a标签下的文本值

文章点赞数量是 class="meta"的 div标签下的 span标签下的文本值

这时候 xpath有很多种写法,我写出其中的两种,一好一坏,大家可以试着判断一下哪个好哪个坏

第一种写法:

xpath_link = '//ul[@class="note-list"]/li/div/a/@href'

xpath_title = '//ul[@class="note-list"]/li/div/a/text()'

xpath_comment_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/a[2]/text()'

xpath_heart_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/span/text()'

第二种写法:

#获取所有 li标签

xpath_items = '//ul[@class="note-list"]/li'

#对每个 li标签再提取

xpath_link = './div/a/@href'

xpath_title = './div/a/text()'

xpath_comment_num = './/div[@class="meta"]/a[2]/text()'

xpath_heart_num = './/div[@class="meta"]/span/text()'

写好 xpath之后,我们开始第二步,获取网页

获取简书的网页如果我们还像之前那样直接请求的话,就会得到一个 403错误,这是因为没有设置请求头。

加上请求头就能解决了[]( ̄▽ ̄)*

第一种 xpath写法对应的代码:

#-*- coding: utf-8 -*

import requests

from lxml import etree

#请求头和目标网址

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'

}

url = 'https://www.jianshu.com/u/472a595d244c'

#第一种写法的 xpath

xpath_link = '//ul[@class="note-list"]/li/div/a/@href'

xpath_title = '//ul[@class="note-list"]/li/div/a/text()'

xpath_comment_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/a[2]/text()'

xpath_heart_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/span/text()'

#获取和解析网页

r = requests.get(url, headers=headers)

r.encoding = r.apparent_encoding

dom = etree.HTML(r.text)

#所有的 链接 标题 评论数 点赞数

links = dom.xpath(xpath_link)

titles = dom.xpath(xpath_title)

comment_nums = dom.xpath(xpath_comment_num)

heart_nums = dom.xpath(xpath_heart_num)

#将每篇文章的链接 标题 评论数 点赞数放到一个字典里

data = []

for i in range(len(links)):

t = {}

t['link'] = links[i]

t['title'] = titles[i]

t['comment_num'] = comment_nums[i].strip()

t['heart_num'] = heart_nums[i].strip()

data.append(t)

#打印结果

for t in data:

print(t)

运行结果如下:

ff37a8524e72

example-3

可以看到,第一篇和第三篇的 comment_num 没有获取到

第二种 xpath写法对应的代码:

#-*- coding: utf-8 -*

import requests

from lxml import etree

#请求头和目标网址

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'

}

url = 'https://www.jianshu.com/u/472a595d244c'

#第二种写法的 xpath

#获取所有 li标签

xpath_items = '//ul[@class="note-list"]/li'

#对每个 li标签再提取

xpath_link = './div/a/@href'

xpath_title = './div/a/text()'

xpath_comment_num = './/div[@class="meta"]/a[2]/text()'

xpath_heart_num = './/div[@class="meta"]/span/text()'

#获取和解析网页

r = requests.get(url, headers=headers)

r.encoding = r.apparent_encoding

dom = etree.HTML(r.text)

#获取所有的文章标签

items = dom.xpath(xpath_items)

#分别对每一个文章标签进行操作 将每篇文章的链接 标题 评论数 点赞数放到一个字典里

data = []

for article in items:

t = {}

t['link'] = article.xpath(xpath_link)[0]

t['title'] = article.xpath(xpath_title)[0]

#comment_num对应的标签里有两个文本标签 用 join方法将两个文本拼接起来

#strip()方法去除换行和空格

t['comment_num'] = ''.join(article.xpath(xpath_comment_num)).strip()

t['heart_num'] = article.xpath(xpath_heart_num)[0].strip()

data.append(t)

#打印结果

for t in data:

print(t)

运行结果:

ff37a8524e72

example-4

这里 comment_num成功获得了

仅仅从获取的结果来看,我们就可以判断第二种 xpath写法更好。

为什么第二种写法更好呢?

因为第二种方法把每一篇文章看作一个对象,这样后续的处理都是以对象为基本单位,对数据进行处理的时候过程更加清晰。

而第一种写法把链接、标题、评论数和点赞数量这四个分别用列表存储,这样虽然同样可以获得结果,但是再进行数据处理的时候就需要考虑怎么才能不破坏四个变量之间的一一对应关系。

用第二种方法就没有这个问题,因为在处理数据的时候它们都被看作同一个对象的组成部分,这本身就蕴含着蕴含着一种关系。

现在问题来了,平时我们在爬取数据的时候,怎么才能判断哪些数据是同一个对象呢?

这个其实很简单,在我们分析需求的时候就已经知道了,我们所需要数据的一个完整组合就是一个对象。

比如在本文的例子里,我们要爬取链接、标题、评论数和点赞数量,那么{链接,标题,评论数,点赞数量}就是一个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值