单元四、信息组织与提取方法
1)信息标记的三种方式
XML, JSON, YAML
2)信息提取的一般方法
-
方法一:完整解析信息的标记形式,再提取关键信息
XML JSON YAML
需要标记解析器 例如:bs4库的标记树遍历
优先:信息解析准确
缺点:提取过程繁琐,速度慢
-
方法二:无标记形式,直接搜索关键信息
搜索
对信息的文本查找函数即可。
优点:提取过程简单,速度较快
缺点:提取结果准确性与信息内容有关
-
方法三:融合方法:结合形式解析与搜索方法,提取关键信息
XML JSON YAML 搜索
需要标记解析器及文本查找函数
实例:提取HTML中所有的URL链接
思路;1)搜索到所有的标签
2)解析标签格式,提取href后的链接内容
3)基于bs4的HTML内容查找方法
<tag>.fint_all(name, attrs, recursive, string, **kwargs)
其等价于<tag>(..)
返回:
一个列表类型,存储查找的结果
选项:
name: 对标签名称的检索字符串
attrs: 对标签属性值的检索字符串,可标注属性索引
recursive: 是否对子孙全部索引,默认True
string: <>...</>中字符串区域的检索字符串
**kwargs:
参数name:
>>> soup.find_all('a') ## 查找所有a标签
>>> soup.find_all(['a', 'b']) ## 查找所有a, b标签
参数attrs:
>>> soup.find_all('p', 'course')
>>> soup.find(id = 'link1')
参数recursive:
>>> soup.find_all('a', recursive = True)
>>> soup.find_all('a', recursive = False)
参数string:
>>> soup.find_all(string = 'Basic Python')
简写:
<tag>(…) 等价于 <tag>.find_all(…)
soup(…) 等价于 soup.find_all(…)
拓展方法:
方法 | 说明 |
---|---|
<>.find() | 搜索且只返回一个结果,字符串类型,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_parent() | 在先辈节点中返回一个结果,字符串类型, 同.find_all()参数 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型, 同.find_all()参数 |
<>.find_next_sibling() | 在后续平行节点中返回一个结果,字符串类型, 同.find_all()参数 |
<>.find_previous_siblings() | 在前续平行节点中搜索,返回列表类型, , 同.find_all()参数 |
<>.find_previous_sibling() | 在前续平行节点中返回一个结果,字符串类型, 同.find_all()参数 |
案例:爬取最好中国大学网
import requests
import bs4
from bs4 import BeautifulSoup
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def fillUnivList(ulist, html):
soup = BeautifulSoup(html, 'html.parser')
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr('td')
ulist.append([tds[0].string, tds[1].string, tds[4].string])
def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tplt.format("排名", "学校", "总分", chr(12288)))
for i in range(num):
u = ulist[i]
print(tplt.format(u[0], u[1], u[2], chr(12288)))
def main():
uinfo = []
url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2020.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20)
main()
单元五、正则表达式
1)正则表达式的概念
正则表达式的常用操作符
操作符 | 说明 | 实例 |
---|---|---|
. | 表示任何单个字符串 | |
[ ] | 字符集,对单个字符给出取值范围 | [abc]表示a、b、c,[a-z]表示a到z单个字符 |
[^ ] | 非字符集,对单个字符给出排除范围 | [^abc]表示非a或b或c的单个字符 |
* | 前一个字符出现0次或无限次拓展 | abc*表示ab、abc、abcc、abccc等 |
+ | 前一个字符出现1次或无限次拓展 | abc+表示abc、abcc、abccc等 |
? | 前一个字符出现0次或1次拓展 | abc?表示ab、abc |
| | 左右表达式任意一个 | abc|def表示abc、def |
{m} | 拓展前一个字符m次 | ab{2}c表示abbc |
{m, n} | 拓展前一个字符m至n次(含n) | ab{1, 2}c表示abc、abbc |
^ | 匹配字符串开头 | ^abc表示abc且在一个字符串的开头 |
$ | 匹配字符串结尾 | abc$表示abc且在一个字符串的结尾 |
() | 分组标记,内部只能使用|操作符 | (abc)表示abc,(abc|def)表示abc、def |
\d | 数字,等价于[0-9] | |
\w | 单词字符,等价于[A-Za-z0-9_] |
2)Re库的使用
Re库主要功能函数
函数 | 说明 |
---|---|
re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回一个match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的迭代对象,每个迭代对象都是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
1 re.search()
re.search(pattern, string, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
string: 待匹配字符串
flags: 正则表达式使用时的控制标记
flags的常用标记:
常用标记 | 说明 |
---|---|
re.I re.IGNORECASE | 忽略正则表达式的大小写,|A-Z|能够匹配小写字符 |
re.M re.MULTILINE | 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始 |
re.S re.DOTALL | 正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符 |
2 re.match
re.match(pattern, string, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
string: 待匹配字符串
flags: 正则表达式使用时的控制标记
3 re.findall
re.findall(pattern, string, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
string: 待匹配字符串
flags: 正则表达式使用时的控制标记
4 re.split
re.split(pattern, string, maxsplit=0, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
string: 待匹配字符串
maxsplits: 最大分割数,剩余部分作为最后一个元素输出
flags: 正则表达式使用时的控制标记
5 re.finditer
re.finditer(pattern, string, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
string: 待匹配字符串
flags: 正则表达式使用时的控制标记
6、re.sub
re.sub(pattern, repl, string, count = 0, flags=0)
选项:
patten: 正则表达式的字符串或原生子串表达式
repl: 替换匹配字符串的字符串
string: 待匹配字符串
count: 匹配的最大替换次数
flags: 正则表达式使用时的控制标记
3)Re库的另一种等价用法
regex = re.compile(pattern, flags = 0)
选项:
patten: 正则表达式的字符串或原生子串表达式
flags: 正则表达式使用时的控制标记
函数 | 说明 |
---|---|
regex.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回一个match对象 |
regex.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
regex.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
regex.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
regex.finditer() | 搜索字符串,返回一个匹配结果的迭代对象,每个迭代对象都是match对象 |
regex.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
4)Re库的match对象
Match对象的属性
属性 | 说明 |
---|---|
.string | 待匹配的文本 |
.re | 匹配时使用的pattern对象(正则表达式) |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
Match对象的方法
方法 | 说明 |
---|---|
.group(0) | 获得匹配后的字符串 |
.start() | 匹配字符串在原始字符串的开始位置 |
.end() | 匹配字符串在原始字符串的结束位置 |
.span() | 返回(.start(), .end()) |
5)Re库的贪婪匹配和最小匹配
Re库默认使用贪婪匹配,即输出匹配最长的子串。
最小匹配操作符
操作符 | 说明 |
---|---|
*? | 前一个字符0次,或无限次扩展,最小匹配 |
+? | 前一个字符1次,或无限次扩展,最小匹配 |
?? | 前一个字符0次,或1次扩展,最小匹配 |
{m, n}? | 拓展前一个字符m至n次(含n),最小匹配 |
单元六、Scrapy爬虫框架
1)Scrapy爬虫框架解析
各个模块说明:
- Engine——控制所有模块的数据流/根据条件触发事件【不需要用户修改】
- Downloader——根据请求下载网页【不需要用户修改】
- Scheduler——对所有爬取请求进行调度管理【不需要用户修改】
- Spiders——解析Downloader返回的响应(Response);产生爬取项(scraped item),产生额外的爬取请求(Request)【需要用户编写配置代码】
- Item Pipelines——以流水线方式处理Spider产生的爬取项;由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型;可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库中。【需要用户编写配置代码】
- ————————————————————————————————————
- Downloader Midderware——实施Engine、Scheduler和Downloader之间进行用户可配置的控制,可实现修改、丢弃、新增请求或响应【用户可编写配置代码】
- Spider Middleware——对请求和爬取项的再处理,可实现修改、丢弃、新增请求或爬取项【用户可编写配置代码】
2)Scrapy爬虫的常用命令
Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scarpy命令行。
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject [dir] |
genspider | 创建一个爬虫 | scrapy genspider [options] |
settings | 获得爬虫配置信息 | scrapy settings [options] |
crawl | 运行一个爬虫 | scrapy crawl |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell [url] |
3)scrapy 爬虫实例
使用scrapy爬取页面:http://www.python123.io/ws/demo.html
步骤:
1 建立一个Scrapy爬虫工程
生成的工程文件
python123demo——》外层目录
scrapy.cfg——》部署Scrapy爬虫的配置文件
python123demo——》Scrapy框架的用户自定义Python代码
__ init __.py——》初始化脚本
items.py——》Items代码模块(继承类)
middlewares.py——》Middlewares代码模板(继承类)
pipelines.py——》Pipelines代码模板(继承类)
settings.py——》Scrapy爬虫的配置文件
spiders/——》Spriders代码模板目录(继承类)
__ init __.py——》初始文件,无需修改
__ pycache __/——》缓存目录,无需修改
2 在工程中产生一个Scrapy爬虫(创建了一个py脚本存放在spiders目录下)
在spiders目录下产生一个demo.py文件,查看文件:
这里的parse()用于处理响应,解析内容形成字典,发现新的URL爬取请求。
3 配置产生的spider爬虫
4 运行爬虫,获取网页
demo.py两个等价版本的区别
yield关键字:
yield 《——》生成器:不断产生值的函数
生成器每次产生一个值(yield语句),就会被冻结,被唤醒后再从上次的位置继续再产生一个值。
4)Scrapy爬虫的基本使用
Scrapy爬虫的使用步骤:
步骤一:创建一个工程和Spider模板
步骤二:编写Spider
步骤三:编写Item Pipeline
步骤四:优化配置策略
Scrapy爬虫的数据类型:
Request类
Response类
Item类
Request类
class.Scrapy.http.Request()
- Request对象表示一个HTTP请求。
- 由Spider生成,由Downloader执行
属性 | 说明 |
---|---|
.url | Request对应的请求URL地址 |
.method | 对应的请求方法,‘GET’‘POST’等 |
.headers | 字典类型风格的请求头 |
.body | 请求内容主体,字符串类型 |
.meta | 用户添加的拓展信息,在Scrapy内部模块间传递信息使用 |
.copy() | 复制该请求 |
Response类
class.Scrapy.http.Response()
- Response对象表示一个HTTP响应。
- 由Downloader成,由Spider处理
属性或方法 | 说明 |
---|---|
.url | Response对应的URL地址 |
.status | HTTP状态码,默认200 |
.headers | Response对应的头部信息 |
.body | Response对应的内容信息,字符串类型 |
.flags | 一组标记 |
.request | 产生Response类型的Request对象 |
.copy | 复制该响应 |
Item类
class.scrapy.item.item()
- Item对象表示一个从HTML页面中提取的信息内容
- 由Spider生成,由Item Pipeline处理
- Item类似字典类型,可以按照字典类型操作
5)Scrapy爬虫提取信息的方法
Scrapy爬虫支持多种HTML信息提取方法:
- Beautiful Soup
- lxml
- re
- XPath Selector
- CSS Selector
CSS Selector的基本使用
<html>.css('a::attr=(href)').extract()
获得对应的标签信息
注:
a:标签名称
href:标签属性
6)配置并发连接选项—settting.py文件
选项 | 说明 |
---|---|
CONCURRENT_REQUESTS | Downloader最大并发下载数量,默认32 |
CONCURRENT_ITEMS | Item Pipeline最大并发ITEM处理数量,默认100 |
CONCURRENT_REQUESTS_PRE_DOMAIN | 每个目标域名最大的并发请求数,默认8 |
CONCURRENT_REQUESTS_PER_IO | 每个目标IP最大的并发请求数,默认为0,非0有效 |
参考资料:
【1】Mooc - Python爬虫与信息提取