小孟先森的博客

一个起步Python程序员的进阶之路

day064 RegularExpresion&Xpath

今天是两个文本处理的工具,re(正则表达式)和Xpath

re

  • re是遵循一定规则的,能够匹配,处理字符串的字符表达式。
  • 它拥有单个字符(.\d,\w,\s…),多个字符(*,?,+…)位置字符(^,$)等能够匹配不同条件下的字符的格式字符和如match(),search(),find(),sub(),split()等在匹配完字符后可以进一步处理数据的方法。
  • 使用场景非常广泛,理论上说,只要匹配字符串的地方,就可以使用re,如flask视图函数url里的选择器,当然,处理爬取的html页面,它也是可以轻松胜任的。

常见使用步骤

  • 1.导入re模块:import re
  • 2.生成一个包含一定匹配条件的pattern对象:pattern = re.compile(r'<匹配条件>')
  • 3.在需要使用的地方,直接调用pattern对象和相应方法:pattern.findall('<待处理的字符串>')

匹配语法:

匹配语法详解

常用方法

1.match():从头开始匹配,匹配一个,返回带有匹配结果的对象,可用group(),获取结果
2.search():从任意位置开始匹配,匹配第一个,返回带有匹配结果的对象,可用group(),获取匹配结果
3.findall():从任意位置匹配,匹配满足条件的所有结果,返回一个列表
4.finditer():跟findall()匹配形式相似,但是返回以迭代器
5.split():将字符串按照一定字符进行切分,返回一个列表
6.sub():按照一定条件替换字符串的某些片段,返回替换后的结果

试例:

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


def test_re():
    str = "there is a place, in your heart, and i know that it is love"

    # match
    match = re.match(r'there', str)
    match2 = re.match(r'ere', str)
    print match
    # <_sre.SRE_Match object at 0x107c47a58>
    print match2
    # None
    print match.group()
    # there

    # search
    search = re.search(r'ere', str)
    print search
    # <_sre.SRE_Match object at 0x10217be00>
    print search.group()
    # ere

    # findall
    findall = re.findall(r'o', str)
    print findall
    # ['o', 'o', 'o']

    # finditer
    findilter = re.finditer(r'o', str)
    print findilter
    # <callable-iterator object at 0x1022f6d10>
    for o in findilter:
        print o.group()
    # o
    # o
    # o

    # sub
    sub = re.sub('there is a place', '', str)
    print sub
    # , in your heart, and i know that it is love

    # split
    split = re.split(' ', str)
    print split
    # ['there', 'is', 'a', 'place,', 'in', 'your', 'heart,', 'and', 'i', 'know', 'that', 'it', 'is', 'love']

if __name__ == '__main__':
    test_re()
  • 在unicode下匹配中文字符
# unicode中文匹配
    str2 = u'我就是i, 是色不一样的fireworks'
    # 匹配字符串中所有的中文字符(u4e00-u9fa5是unicode中所有的中文字符,不包括全角的中文标点)
    chinese = re.findall(ur'[\u4e00-\u9fa5]+', str2)
    print chinese
    # [u'\u6211\u5c31\u662f', u'\u662f\u8272\u4e0d\u4e00\u6837\u7684']
    word = chinese[0].encode('utf-8')
    print word
    # 我就是

Xpath

预备知识点

  • XML:扩展标记语言,是一种主要用来传输数据的文件格式

    • 由成对的标签组成,跟HTML文件格式很像,但是标签名是不固定的,是可以根据需求自定义的
    • xml本身 是没有任何功能的,就是普通的文本内容
  • Ixml:是一个用来解析XML/HTML文件的解析器,使用Ixml里的etree方法,可以将字符串形式的HTML/XML或者普通的XML/HTML文件解析成节点组成的树状结构。这种结构可以使用Xpath 语言进行导航

  • X path 是用来导航xml文件的一种语言,有自己的语法和函数库,可以对被Ixml解析的HTML/XML文本进行检索匹配

Xpath的语法

  • 基本语法
    • /:从根节点开始
    • //:从任意节点开始
    • .:当前节点
    • ..:父级节点
    • @:获取属性
  • 属性选择
    • []:对[]之前的节点进行属性/方法约束
  • 其他

    • *:任意,加在节点后表示任意节点,加在@后表示任意属性
    • |: 或者,相当于|两边的节点并集

    • 使用步骤:

    • 1.导入ixml库的etree方法:from ixml import etree
    • 2.使用etree.HTML(<字符串>)/etree.parse(<文件>)来读取需要解析的字符串或者文件
    • 3.对解析后的对象使用<对象名>.xpath(<条件>)进行导航

    示例:

 # -*- coding:utf-8 -*-
from lxml import etree


def test_xpath_use():
    str = """
        <html><body>
    <div>
        <ul>
             <li class="item-0"><a href="link1.html">first item</a></li>
             <li class="item-1"><a class="bold" href="link2.html">second item</a></li>
             <li class="item-inactive"><a class='link3' href="link3.html">third item</a></li>
             <li class="item-1"><a href="link4.html">fourth item</a></li>
             <li class="item-0"><a href="link5.html">fifth item</a></li>
    </ul>
     </div>
    </body></html>

    """
    # 解析字符串文本
    html = etree.HTML(str)

    # 使用.xpath对html对象所有节点及属性进行导航
    # 获取所有的 <li> 标签
    res = html.xpath('//li')
    print res
    # [<Element li at 0x1043053b0>, <Element li at 0x104305440>, <Element li at 0x1043054d0>, <Element li at 0x104305518>, <Element li at 0x104305560>]

    # 获取<li> 标签的所有 class属性
    res = html.xpath('//li/@class')
    print res
    # ['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']

    # 获取<li>标签下href 为 link1.html 的 <a> 标签
    res = html.xpath("//li/a[@href='link1.html']")
    print res
    # [<Element a at 0x10254a638>]

    # 获取<li> 标签下的所有 <span> 标签
    res = html.xpath('//li//span')
    print res
    # []

    # 获取 <li> 标签下的<a>标签里的所有 class
    res = html.xpath('//li/a/@class')
    print res
    # ['link3']

    # 获取最后一个 <li> 的 <a> 的 href
    res = html.xpath('//li[last()]/a/@href')
    print res
    # ['link5.html']

    # 获取倒数第二个li元素的<a>内容
    res =html.xpath('//li[last()-1]/a')
    print res[0].text # .test表示标签的内容
    # fourth item

    # class 值为 bold 的标签名
    res = html.xpath('//*[@class="bold"]') # //或者/是必须要加的,表示从哪里开始
    print res[0].tag # .tag表示获取标签的名字
    # a

if __name__ == '__main__':
    test_xpath_use()

案例

爬取某个贴吧里的所有帖子,并且将该这个帖子里每个楼层发布的图片下载到本地

代码:

# !/usr/bin/env python
# _*_ coding:utf-8 _*_


import urllib2
import urllib
from lxml import etree


class Tieba_Spider(object):
    def __init__(self):
        self.base_url = 'http://tieba.baidu.com/f?'
        self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"}

        # 解析 第一层  url 注意浏览器的xpath插件 只是辅助,  自动过滤空格
        # self.frist_url = '//a[@class="j_th_tit "]/@href'
        self.frist_url = '//div[@class="t_con cleafix"]/div/div/div/a/@href'

        # 第二层
        self.second_url = '//img[@class="BDE_Image"]/@src'

    # 发送请求
    def send_request(self, url):
        request = urllib2.Request(url, headers=self.headers)
        response = urllib2.urlopen(request)
        data = response.read()

        return data

    # 保存本地文件
    def write_file(self, data, image_name):
        print image_name
        file_path = 'images/' + image_name
        with open(file_path, 'w') as f:
            f.write(data)

    # 解析数据
    def analysis_data(self, data, xpathStr):
        # 1.转换 类型 可解析的类型
        html_data = etree.HTML(data)
        # 2.解析
        result_list = html_data.xpath(xpathStr)

        return result_list

    # 调度方法 start_work
    def start_work(self):
        # 贴吧的名字
        tieba_name = '美食'  # raw_input('请输入抓取的贴吧名字:')
        # 开始的页数
        start_page = 1  # int(raw_input('请输入开始页数:'))
        # 结束的页数
        end_page = 1  # int(raw_input('请输入结束页数:'))

        # 开启循环
        for page in range(start_page, end_page + 1):
            pn = (page - 1) * 50
            # 发送请求
            params = {
                'kw': tieba_name,
                'pn': pn
            }

            # 网址的转译
            params_str = urllib.urlencode(params)
            new_url = self.base_url + params_str
            data = self.send_request(new_url)

            # 第二层  获取 每一个 子链接  发送请求
            link_list = self.analysis_data(data, self.frist_url)
            print link_list
            for link in link_list:
                child_url = 'http://tieba.baidu.com' + link

                second_data = self.send_request(child_url)

                # 第三层  获取图片的url  发送图片的请求
                image_list = self.analysis_data(second_data,self.second_url)

                for image_url in image_list:

                    # 发送图片的请求 保存到本地
                    image_data = self.send_request(image_url)
                    # 文件名字
                    image_name = image_url[-20:]
                    self.write_file(image_data, image_name)

if __name__ == '__main__':
    tool = Tieba_Spider()
    tool.start_work()

阅读更多

扫码向博主提问

去开通我的Chat快问

VisionaryX

非学,无以致疑;非问,无以广识
版权声明:本文为博主原创文章,未经博主允许请随意转载。 https://blog.csdn.net/Michael_Cool/article/details/79967287
个人分类: 学习日志
上一篇day067 mongoDB_advance&amp;反爬虫&amp;反反爬虫
下一篇day069 Scrapy_base_use
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭