黑马python2.7的爬虫2-非结构化数据与结构化数据提取

非结构化数据与结构化数据提取

抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据 和 结构化的数据。

  • 非结构化数据:先有数据,再有结构,
  • 结构化数据:先有结构、再有数据
  • 不同类型的数据,我们需要采用不同的方式来处理。

1、非结构化的数据处理

文本、电话号码、邮箱地址
  • 正则表达式
HTML 文件
  • 正则表达式
  • XPath
  • CSS选择器

2、结构化的数据处理

JSON 文件
  • JSON Path
  • 转化成Python类型进行操作(json类)
XML 文件
  • 转化成Python类型(xmltodict)
  • XPath
  • CSS选择器
  • 正则表达式

爬虫一共就四个主要步骤:

  1. 明确目标 (要知道你准备在哪个范围或者网站去搜索)
  2. 爬 (将所有的网站的内容全部爬下来)
  3. 取 (去掉对我们没用处的数据)
  4. 处理数据(按照我们想要的方式存储和使用)

1、正则表达式

正则表达式和另一个字符串可以匹配和过滤

正则有字符.,字符集\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]

注意:贪婪模式(多)与非贪婪模式(少)

  1. Python里数量词默认是贪婪的。

默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式。

解码

gbk_html = html.decode('gbk').encode('utf-8')

values = ",".join(map(str, value_list)) #列表转字符串

python 字符串(str)和列表(list)的互相转换      re.S全文匹配 re.I忽略大小写


.*?点代表的是任意字符。* 代表的是取 0 至 无限长度问号代表的是非贪婪模式。三个链接在一起是取尽量少的任意字符

实战1 使用正则表达式的爬虫

这个案例能学到很多,好好学,思考


正则用的不好,处理HTML文档很累,有没有其他的方法?

有!那就是XPath,我们可以先将 HTML文件 转换成 XML文档,然后用 XPath 查找 HTML 节点或元素。

2、XML

父,子,同胞,先辈,后代

最常用的路径表达式:

表达式 描述
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;"}

实战2 使用XPath的爬虫

学会保存图片,检测文件夹是否存在,否则建立新文件夹,使用init函数

3、CSS 选择器:BeautifulSoup4

Beautiful Soup 4.4.0 文档

抓取工具 速度 使用难度 安装难度
正则 最快 困难 无(内置)
BeautifulSoup 最简单 简单
lxml 简单 一般
各种工具抓取时间对比

对象种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

  • Tag 通俗点讲就是 HTML 中的一个个标签
  • NavigableString
  • BeautifulSoup
  • Comment

1. Tag

#创建 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

2. NavigableString

既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如

print soup.p.string
# The Dormouse's story
print type(soup.p.string)
# In [13]: 

3. BeautifulSoup

BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性来感受一下

print type(soup.name)
# 

print soup.name 
# [document]

print soup.attrs # 文档本身的属性为空
# {}

4. Comment

Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。

print soup.a
# 

遍历文档树

jquery选择器类似

搜索文档树

1.find_all(name, attrs, recursive, text, **kwargs)


name可以传正则 如:
import re
for tag in soup.find_all(re.compile("^b")):
    print(tag.name)
# body
# b

CSS选择器 (超级好用哦)

这就是另一种与 find_all 方法有异曲同工之妙的查找方法.

  • 写 CSS 时,标签名不加任何修饰,类名前加.,id名前加#

  • 在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select()

print soup.select('b')
select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。

实战3 使用BeautifuSoup4的爬虫

 学会存储为json格式,哈哈

4、数据提取之JSON与JsonPATH

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。

JSON和XML的比较可谓不相上下。

JSON

json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构

  1. 对象:对象在js中表示为{ }括起来的内容,数据结构为 { key:value, key:value, ... }键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种。

  2. 数组:数组在js中是中括号[ ]括起来的内容,数据结构为 ["Python", "javascript", "C++", ...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。

json模块提供了四个功能: 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

JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, PHP 和 Java。

JsonPath 对于 JSON 来说,相当于 XPATH 对于 XML。

超级干货python编码

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字符集进行编码的一种编码方式

实战4 糗事百科

爬取糗事百科段子,假设页面的URL是  http://www.qiushibaike.com/8hr/page/1

  1. 使用requests获取页面信息,用XPath / re 做数据提取

  2. 获取每个帖子里的用户头像链接用户姓名段子内容点赞次数评论次数

  3. 保存到 json 文件内

使用requests高级  错误处理 xpath

经典实战5 多线程糗事百科

多看视频,看起来有点难,线程,队列

Queue(队列对象)

对于资源,加锁是个重要的环节。因为python原生的list,dict等,都是not thread safe的。而Queue,是线程安全的,因此在满足使用条件下,建议使用队列

  1. 初始化: class Queue.Queue(maxsize) FIFO 先进先出

  2. 包中的常用方法:

    • Queue.qsize() 返回队列的大小

    • Queue.empty() 如果队列为空,返回True,反之False

    • Queue.full() 如果队列满了,返回True,反之False

    • Queue.full 与 maxsize 大小对应

    • Queue.get([block[, timeout]])获取队列,timeout等待时间

  3. 创建一个“队列”对象

    • import Queue
    • myqueue = Queue.Queue(maxsize = 10)
  4. 将一个值放入队列中

    • myqueue.put(10)
  5. 将一个值从队列中取出

    • myqueue.get()
黑马python2.7的爬虫2-非结构化数据与结构化数据提取_第1张图片




































你可能感兴趣的:(编程语言)