美文网首页
第四章 网站内容爬取之xpath选择器在某个网页上的实践

第四章 网站内容爬取之xpath选择器在某个网页上的实践

作者: 田同学的小迷妹儿 | 来源:发表于2018-08-27 20:58 被阅读75次

如何通过xpath在html中取出想要的值:scrapy根据xml提供了一套简洁的通过xpath或者css选择器来提取数据的接口。

4.1 关于xpath

  • xpath简介:xpath使用路径表达式(就像windows系统文件的路径一样可以定位)在xml和html中进行导航,包含了很多标准函数库,xpath包含有一个标准函数库,xpath是一个w3c的标准
  • xpath术语
  • xpath语法

xpath节点关系:
html中被尖括号包起来的被称为一个节点。

  1. 父节点 上一层节点
  2. 子节点 下一层节点
  3. 兄弟节点 同胞节点
  4. 先辈节点 父节节点,爷爷节点
  5. 后代节点 儿子节点,孙子节点

4.2 xpath语法

表达式 说明
article 选取所有article元素的所有子节点
/article 选取根元素article(html中根元素都是html;xml可以自定义根节点)
article/a 选取所有属于article的子元素的a元素
//div 选取所有div元素(不管出现在文档里的任何地方)
article//div 选取所有属于article元素的后代的div元素,不管它出现在article之下的任何位置
//@class 选取所有名为class的属性
xpath语法-谓语
表达式 说明
/article/div[1 选取属于article子元素的第一个div元素
/article/div[last()] 选取属于article子元素的最后一个div元素
/article/div[last()-1] 选取属于article子元素的倒数第二个div元素
//div[@color] 选取所有拥有color属性的div元素
//div[@color='red'] 选取所有color属性值为red的div元素
xpath语法
表达式 说明
/div/* 选取属于div元素的所有子节点
//* 选取所有元素
//div[@*] 选取所有带属性的div 元素
//div/a 丨//div/p 选取所有div元素的a和p元素
//span丨//ul 选取文档中的span和ul元素
article/div/p丨//span 选取所有属于article元素的div元素的p元素以及文档中所有的 span元素

4.3 xpath选择器在具体网站上的应用

以伯乐在线的这篇文章为例,http://blog.jobbole.com/110287/,我们想获取,正文部分的标题,首先要做的就是F12检查元素,然后去找到这个标题对应的html节点位置:

可以看到,我们的标题标题在 html/body/div[1]/div[3]/div[1]/div[1]/h1 这个嵌套关系下,我们在用xpath解析的时候,不需要自己一个一个地看嵌套关系,在 F12下,在某个元素上面右键即copy->copy xpath就能获得该元素的xpath路径。
注意:在Firefox和chrom浏览器中右键copy xpath得到的结果可能不一样

在Firefox中,得到的路径是/html/body/div[1]/div[3]/div[1]/div[1]/h1
在chrom中,得到的是//*[@id="post-110287"]/div[1]/h1
可以发现两种路径不一样,经过测试,第一种路径不能获得标题,第二种可以,原因在于,一般元素检查看到的是动态的返回来的html信息,比如js生成的,然后有些节点可能是在后台返回信息时才创建的,对于静态的网页就是检查源代码,定位的结果可能不一样,采用第二种id确定的方式更容易标准的定位。

用xpath提取标题的案例:
# -*- coding: utf-8 -*-
import scrapy

class JobboleSpider(scrapy.Spider):
    name = "jobbole"
    allowed_domains = ["blog.jobbole.com"]
    start_urls = ['http://blog.jobbole.com/110287/']

    def parse(self, response):
        # 取任何节点。id等于post-110287.
        # re_selector = response.xpath('/html/body/div[1]/div[3]/div[1]/div[1]/')
        # re_selector = response.css('#post-95104 > div.entry-header > h1')
        re_selector = response.xpath('//*[@id="post-110287"]/div[1]/h1')
        print(re_selector)
        pass

# 通过debug断点调试,可以看到返回来的re_selector是有正确信息的,定位到了h1这个节点

通过调试可以看到结果:

错误提示:

同一个页面的元素通过不同电脑的chrom浏览器进行源代码查看,标签结点信息发现不一样,在h1标签中多了个span标签,解决方法:清除浏览器缓存,以下是同一页面用一个内容的检查元素的对比图。

图1:未清除浏览器缓存前



图2:清除浏览器缓存后


4.4 使用shell命令调试及更多字段内容爬取

介绍一个技巧,每次调试启动scrapy是比较慢的,每次调试都请求了一次url,效率比较低

scrapy提供了一种shell模式,提高了调试的效率。具体操作方法是在命令行中,之前的启动scrapy的命令是scrapy crawl jobbole,现在可以在命令行中使用shell,命令为“scrapy shell 网址”,然后就进入了调试区域。步骤如下图,注意启动scrapy必须在命令行中进入相应的虚拟环境以及项目的工作目录

获取发布时间:
response.xpath("//p[@class = 'entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·","").strip()

关于发布时间的标签设计:

在shell模式下的调试步骤:

获取点赞数:
int(response.xpath("//span[contains(@class,'vote-post-up')]/h10/text()").extract()[0])
# contains(属性名,内容)之所以用这个方法因为
#该span标签的class属性里面布置一个值,所以用contains()这个函数

在shell模式下的调试步骤:

获取收藏数:
response.xpath("//span[contains(@class,'bookmark-btn')]/text()").extract()[0]
# '  收藏'
# 收藏数的标签设置和点赞数不一样,直接是收藏前面有数字,这里没有数字,其实是0收藏的意思。
# 对于含数字的话,我们应该使用正则表达式将数字部分提取出来。

import re
match_re = re.match('.*?(\d+).*',' 收藏')
if match_re:
    fav_nums = int(match_re.group(1))
else:
    fav_nums = 0
# 正则表达式注意要有?表示非贪婪匹配,可以获取两位数等
# 还有一点就是老师没有考虑的,如果没有收藏数,即匹配不到数字,说明收藏数为0.
获取评论数:
# 评论数和收藏数的标签设计是一样的,只需要更改xpath即可
comment_nums = response.xpath("//a[@href='#article-comment']/span/text()").extract()[0]
        match_re = re.match('.*?(\d+).*', comment_nums)
        if match_re:
            comment_nums = int(match_re.group(1))
        else:
            comment_nums = 0
获取正文内容:
content = response.xpath('//div[@class="entry"]').extract()[0]
# 对于文章内容,不同网站的设计不一样,我们一般保存html格式的内容

关于extract()方法和text()方法的区别:extract()是对一个selector的内容取出这个标签内的所有内容,包括当前的节点标签。text()方法一般是在xpath的路径内部,用于获取当前节点内的所有文本内容。

获取文章类型:
tag_list = response.xpath("//p[@class = 'entry-meta-hide-on-mobile']/a/text()").extract()
        tag_list = [element for element in tag_list if not element.strip().endswith("评论")]
        # 有的网页在类型一栏中会得到评论数,以前的老设计,所以需要将关于评论的这一项去掉
        tags = ",".join(tag_list)

4.5 xpath选择器在伯乐在线文章上的爬取实例

最后关于http://web.jobbole.com/95104/这个网页,我们一次获取了标题,创建日期,点赞数,收藏数,评论数,正文内容,以及文章类型,整个实现过程都是用的xpath选择器,实现代码如下:

# -*- coding: utf-8 -*-
import scrapy
import re

class JobboleSpider(scrapy.Spider):
    name = "jobbole"
    allowed_domains = ["web.jobbole.com"]
    start_urls = ['http://web.jobbole.com/95104/']

    def parse(self, response):
        # 取任何节点。id等于post-110287.
        #re_selector = response.css('#post-95104 > div.entry-header > h1')
        # re_selector = response.xpath('//*[@id="post-95104"]/div[1]/h1/text()')
        # 在xpath的路径后面添加一个text()方法就可以获得标签里面的标题内容了
        title = response.xpath('//*[@id="post-95104"]/div[1]/h1/text()').extract()[0]
        create_date = response.xpath("//p[@class = 'entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·", "").strip()
        praise_ums = response.xpath("//span[contains(@class,'vote-post-up')]/h10/text()").extract()[0]
        if praise_ums:
            praise_ums = int(praise_ums)
        else:
            praise_ums = 0

        fav_nums = response.xpath("//span[contains(@class,'bookmark-btn')]/text()").extract()[0]
        match_re = re.match('.*?(\d+).*',fav_nums)
        if match_re:
            fav_nums = int(match_re.group(1))
        else:
            fav_nums = 0

        comment_nums = response.xpath("//a[@href='#article-comment']/span/text()").extract()[0]
        match_re = re.match('.*?(\d+).*', comment_nums)
        if match_re:
            comment_nums = int(match_re.group(1))
        else:
            comment_nums = 0

        content = response.xpath('//div[@class="entry"]').extract()[0]
        # 对于文章内容,不同网站的设计不一样,我们一般保存html格式的内容

        tag_list = response.xpath("//p[@class = 'entry-meta-hide-on-mobile']/a/text()").extract()
        tag_list = [element for element in tag_list if not element.strip().endswith("评论")]
        tags = ",".join(tag_list)

        print(title)
        print(create_date)
        print(praise_ums)
        print(fav_nums)
        print(comment_nums)
        print(content)
        print(tags)
        pass

相关文章

网友评论

      本文标题:第四章 网站内容爬取之xpath选择器在某个网页上的实践

      本文链接:https://www.haomeiwen.com/subject/dctxwftx.html