非结构化数据与结构化数据提取
抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据 和 结构化的数据。
爬虫一共就四个主要步骤:
正则表达式和另一个字符串可以匹配和过滤
正则有字符.,字符集\d,数量词*,边界匹配^,分组|,特殊构造组成。
使用步骤:编译……查找……匹配
Pattern 对象的一些常用方法主要有:
- match 方法:从起始位置开始查找,一次匹配
- search 方法:从任何位置开始查找,一次匹配
- findall 方法:全部匹配,返回列表
- finditer 方法:全部匹配,返回迭代器
- split 方法:分割字符串,返回列表
- sub 方法:替换
获得整个匹配的子串时,可直接使用 group() 或 group(0)
findall 全匹配,返回列表
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。
sub 方法用于替换
print p.sub(r'\2 \1', s) # 引用分组
匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围 主要在 [u4e00-u9fa5]
默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式。
gbk_html = html.decode('gbk').encode('utf-8')
values = ",".join(map(str, value_list)) #列表转字符串
python 字符串(str)和列表(list)的互相转换 re.S全文匹配 re.I忽略大小写
.*?点代表的是任意字符。* 代表的是取 0 至 无限长度问号代表的是非贪婪模式。三个链接在一起是取尽量少的任意字符
这个案例能学到很多,好好学,思考
正则用的不好,处理HTML文档很累,有没有其他的方法?
有!那就是XPath,我们可以先将 HTML文件 转换成 XML文档,然后用 XPath 查找 HTML 节点或元素。
最常用的路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
选取分主语谓语
lxml 可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。
选取类似css选择器,比较多,不复杂
init函数可以放好多默认值
def __init__(self):
self.tiebaname=raw_input('请输入要访问的贴吧:')
self.beginPage = int(raw_input("请输入起始页:"))
self.endPage = int(raw_input("请输入终止页:"))
self.url='http://tieba.baidu.com/f'
self.ua_header={"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1 Trident/5.0;"}
学会保存图片,检测文件夹是否存在,否则建立新文件夹,使用init函数
Beautiful Soup 4.4.0 文档
抓取工具 | 速度 | 使用难度 | 安装难度 |
---|---|---|---|
正则 | 最快 | 困难 | 无(内置) |
BeautifulSoup | 慢 | 最简单 | 简单 |
lxml | 快 | 简单 | 一般 |
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
#创建 Beautiful Soup 对象
soup = BeautifulSoup(html)
print soup.title
# The Dormouse's story
print soup.head
# The Dormouse's story
print soup.a
#
print soup.p
# The Dormouse's story
print type(soup.p)
#
Tag,它有两个重要的属性,是 name 和 attrs
print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
# 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。
print soup.p['class'] # soup.p.get('class')
# ['title'] #还可以利用get方法,传入属性的名称,二者是等价的
soup.p['class'] = "newClass"
print soup.p # 可以对这些属性和内容等等进行修改
# The Dormouse's story
del soup.p['class'] # 还可以对这个属性进行删除
print soup.p
# The Dormouse's story
既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如
print soup.p.string
# The Dormouse's story
print type(soup.p.string)
# In [13]:
BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性来感受一下
print type(soup.name)
#
print soup.name
# [document]
print soup.attrs # 文档本身的属性为空
# {}
Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
print soup.a
#
jquery选择器类似
find_all(name, attrs, recursive, text, **kwargs)
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
这就是另一种与 find_all 方法有异曲同工之妙的查找方法.
写 CSS 时,标签名不加任何修饰,类名前加.
,id名前加#
在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select()
print soup.select('b')
select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。
学会存储为json格式,哈哈
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。
JSON和XML的比较可谓不相上下。
json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构
json模块提供了四个功能:
对象:对象在js中表示为
{ }
括起来的内容,数据结构为{ key:value, key:value, ... }
的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种。数组:数组在js中是中括号
[ ]
括起来的内容,数据结构为["Python", "javascript", "C++", ...]
,取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。
dumps
、
dump
、
loads
、
load
,用于字符串 和 python数据类型间进行转换。
loads 把Json格式字符串解码转换成Python对象
strList = '[1, 2, 3, 4]
strDict = '{"city": "北京", "name": "大猫"}'
json.loads(strList)
# [1, 2, 3, 4]
dumps python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串
listStr = [1, 2, 3, 4]
tupleStr = (1, 2, 3, 4)
dictStr = {"city": "北京", "name": "大猫"}
json.dumps(listStr)
# '[1, 2, 3, 4]'
json.dumps(tupleStr)
# '[1, 2, 3, 4]'
dump Python内置类型序列化为json对象后写入文件
listStr = [{"city": "北京"}, {"name": "大刘"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)
load 读取文件中json形式的字符串元素 转化成python类型
strList = json.load(open("listStr.json"))
print strList
# [{u'city': u'\u5317\u4eac'}, {u'name': u'\u5927\u5218'}]
strDict = json.load(open("dictStr.json"))
JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, PHP 和 Java。
JsonPath 对于 JSON 来说,相当于 XPATH 对于 XML。
json.loads() 是把 Json格式字符串解码转换成Python对象,如果在json.loads的时候出错,要注意被解码的Json字符的编码。
如果传入的字符串的编码不是UTF-8的话,需要指定字符编码的参数 encoding
dataDict = json.loads(jsonStrGBK);
字符编码
##字符串编码转换
这是中国程序员最苦逼的地方,什么乱码之类的几乎都是由汉字引起的。
其实编码问题很好搞定,只要记住一点:
####任何平台的任何编码 都能和 Unicode 互相转换
UTF-8 与 GBK 互相转换,那就先把UTF-8转换成Unicode,再从Unicode转换成GBK,反之同理。
``` python
# 这是一个 UTF-8 编码的字符串
utf8Str = "你好地球"
# 1. 将 UTF-8 编码的字符串 转换成 Unicode 编码
unicodeStr = utf8Str.decode("UTF-8")
# 2. 再将 Unicode 编码格式字符串 转换成 GBK 编码
gbkData = unicodeStr.encode("GBK")
# 1. 再将 GBK 编码格式字符串 转化成 Unicode
unicodeStr = gbkData.decode("gbk")
# 2. 再将 Unicode 编码格式字符串转换成 UTF-8
utf8Str = unicodeStr.encode("UTF-8")
decode
的作用是将其他编码的字符串转换成 Unicode 编码
encode
的作用是将 Unicode 编码转换成其他编码的字符串
一句话:UTF-8是对Unicode字符集进行编码的一种编码方式
使用requests获取页面信息,用XPath / re 做数据提取
获取每个帖子里的用户头像链接
、用户姓名
、段子内容
、点赞次数
和评论次数
保存到 json 文件内
使用requests高级 错误处理 xpath
Queue(队列对象)
对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列
初始化: class Queue.Queue(maxsize) FIFO 先进先出
包中的常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列,timeout等待时间
创建一个“队列”对象
将一个值放入队列中
将一个值从队列中取出