今天是两个文本处理的工具,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()