爬虫学习(三)

前言

上篇文章我们使用了原生正则表达式来解析网页,这次我们使用xpath来解析网页

正文

安装xpath

pip install lxml

开始xpath

  • 使用Xpath需要从lxml库中导入etree模块,还需使用HTML类对需要匹配的HTML对象进行初始化。HTML类的基本语法格式如下。

    lxml.etree.HTML(text, parser=None, *, base_url=None)
    
    参数名称 说明
    text 接收str。表示需要转换为HTML的字符串。无默认值
    parser 接收str。表示选择的HTML解析器。无默认值
    base_url 接收str。表示设置文档的原始URL,用于在查找外部实体的相对路径。默认为None
  • Xpath使用类似正则的表达式来匹配HTML文件中的内容,常用匹配表达式如下。

    表达式 说明
    nodename 选取nodename节点的所有子节点
    / 从当前节点选取直接子节点
    // 从当前节点选取子孙节点
    . 选取当前节点
    选取当前节点的父节点
    @ 选取属性
  • Xpath中的谓语用来查找某个特定的节点或包含某个指定的值的节点,谓语被嵌在路径后的方括号中,如下。

表达式 说明
/html/body/div[1] 选取属于body子节点下的第一个div节点
/html/body/div[last()] 选取属于body子节点下的最后一个div节点
/html/body/div[last()-1] 选取属于body子节点下的倒数第二个div节点
/html/body/div[positon()<3] 选取属于body子节点下的下前两个div节点
/html/body/div[@id] 选取属于body子节点下的带有id属性的div节点
/html/body/div[@id=”content”] 选取属于body子节点下的id属性值为content的div节点
/html /body/div[xx>10.00] 选取属于body子节点下的xx元素值大于10的节点
  • Xpath中还提供功能函数进行模糊搜索,有时对象仅掌握了其部分特征,当需要模糊搜索该类对象时,可使用功能函数来实现,具体函数如下。
功能函数 示例 说明
starts-with //div[starts-with(@id,”co”)] 选取id值以co开头的div节点
contains //div[contains(@id,”co”)] 选取id值包含co的div节点
and //div[contains(@id,”co”)andcontains(@id,”en”)] 选取id值包含co和en的div节点
text() //li[contains(text(),”first”)] 选取节点文本包含first的div节点

了解了xpath,现在开始编写程序

  • 需求: 还是和上一篇一样,只是今天我们需要把每篇新闻的文字正文保存到本地

  • 我们先用浏览器的调试工具获取一下某个元素的xpath测试一下

    • 审查元素后->右键->copy->copy xpath

    [外链图片转存失败(img-XGDA9UJY-1564032836940)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
    得到结果

    //*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a
    

    我们可以结合上面过于xpath用法的表来看看这个xpath大家能理解不
    我们加上text()获取一下标签内的文本

    //*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a/text()
    
  • 测试程序

    # @File:    code04.py
    # @Author:  lengwen
    # @Time:    2019-07-25 11:37
    # @Desc:    xpath测试程序
    
    
    import requests
    
    from lxml import etree
    url = 'http://www.163.com'
    resp = requests.get(url)
    # 初始化etree  转换为xpath
    html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
    # 使用xpath获取内容
    result1 = html_etree.xpath('//*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a/text()')
    print(result1)
    
    • 结果
      [外链图片转存失败(img-QNMuXDVE-1564032836942)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
  • 接下来进入正题,我们先找到新闻链接的位置,这次我们就不使用浏览器的调试工具直接获取xpath了,因为大家开始看到那个xpath太长了

    [外链图片转存失败(img-7vIRt5DM-1564032836943)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]

    • 根据xpath规则和我们昨天找到的共性我们构建出xpath
    //div[@class="news_default_yw"]/ul/li/a[starts-with(@href,"https://news.163.com/")]/@href
    
    • 这样我们现在得到了所以新闻的URL
    • 然后我们将它保存到本地,方便后面使用
    • 编写程序
      # @File:    code05.py
      # @Author:  lengwen
      # @Time:    2019-07-25 12:01
      # @Desc:    xpath正式开始
      
      import requests
      
      from lxml import etree
      
      url = 'http://www.163.com'
      resp = requests.get(url)
      # 初始化etree  转换为xpath
      html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
      # 构建xpath
      result_url_list = html_etree.xpath(
          '//div[@class="news_default_yw"]/ul/li/a[starts-with(@href,"https://news.163.com/")]/@href')
      # 以写的方式打开url_list.txt这个文件
      with open('./url_list.txt', 'w') as f:
          for i in result_url_list:
              print(i)
              f.write(i + "\n")
      
    • 结果
      [外链图片转存失败(img-EDJS4MWh-1564032836943)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]

接下来我们该爬取每个新闻的文字正文了

  • 随便点进去一个链接可以看到文章的正文都在div.post_text>p中,也就是我们构建xpath渠道div.post_text下的所有p的文字就可以了

  • 构建xpath

    //div[@class="post_text"]/p/text()
    
  • 先看一段调试程序

    # @File:    code06.py
    # @Author:  lengwen
    # @Time:    2019-07-25 12:26
    # @Desc:    爬取新闻
    
    import requests
    from lxml import etree
    
    with open('./url_list.txt') as f:
        url = f.readline()
        resp = requests.get(url)
        html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
        text = html_etree.xpath('//div[@class="post_text"]/p/text()')
        for i in text:
            print(i)
    

    没有注释大家应该也能看懂了

  • 结果
    [外链图片转存失败(img-YE3RaXgb-1564032836944)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]

  • 然后我们只需要加上循环,以及将爬取下来的内容保存就可以了

  • 接下来看程序

    # @File:    code06.py
    # @Author:  lengwen
    # @Time:    2019-07-25 12:26
    # @Desc:    爬取新闻
    
    import requests
    from lxml import etree
    import os
    
    # 创建一个文件夹用于保存新闻
    file_dir = 'news'
    # 判断文件夹是否存在,不存在则创建
    if not os.path.exists(file_dir):
        os.mkdir(file_dir)
    
    with open('./url_list.txt') as f:
        # 按行读取文件
        url = f.readline()
        while url:
            resp = requests.get(url)
            html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
            text = html_etree.xpath('//div[@class="post_text"]/p/text()')
            # 获取标题作为文件名
            title = html_etree.xpath('//title/text()')
            print(title, '保存完成')
            with open(os.path.join(file_dir, title[0] + '.txt'), 'w') as fw:
                for i in text:
                    fw.write(i + '\n')
            url = f.readline()
    
    
  • 结果
    [外链图片转存失败(img-JXVz9A39-1564032836945)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
    [外链图片转存失败(img-0bK1HWFL-1564032836946)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]

关于xpath的部分到此结束

你可能感兴趣的:(爬虫,Python)