视频资源:https://www.bilibili.com/video/BV1NW411V7CQ
单元1:熟悉request库
简单爬取百度首页
import requests # 引入requests 库
r = requests.get('https://baidu.com') # 请求百度首页
r.status_code # 打印返回的状态码
r.encoding= 'utf-8' # 设置编码
r.text # 打印爬取内容
requests库方法介绍
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑以下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应HTTP的GET |
requests.head() | 获取HTML网页头信心的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应HTTP的POST |
requests.put() | 向HTML网页提交PUT请求方法,对应HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改信息,对应HTTP的PATCH |
requests.delete() | 向HTML网页体提交删除请求,对应HTTP的DELETE |
requests.get(url,params=Node,**kwargs)
url: 拟获取页面的url链接
params:url中的额外参数,字典或字节流格式,可选
**kwargs:12个控制访问的参数
get
方法 其实是对request
方法的封装
Response对象的属性
属性 | 说明 |
---|---|
r.status_code | HTTP请求的返回状态,200表示连接成功,404表示失败 |
r.text | HTTP响应内容的字符串形式,即,url对应的页面内容 |
r.encoding | 从HTTPheader中猜测的相应内容编码方式,如果header中没有charset属性就,则默认编码格式是ISO-8859-1 |
r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码方式) |
r.content | http相应内容的二进制形式 |
理解Requests库异常
异常 | 说明 |
---|---|
requests.HTTPError | HTTP错误异常 |
reuqests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大重定向数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时产生超时异常 |
获取异常
异常 | 说明 |
---|---|
r.raise_for_status() | 如果不是200,产生异常requests.HTTPError |
通用框架
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status() #如果状态不是200 引发HTTPError异常
r.encoding = r.apparent_encoiding
return r.text
except:
return '产生异常'
if __name__ == "__main__":
url = 'https://baidu.com'
print(getHTMLText(url))
HTTP协议
HTTP,Hypertext Transfer Protocol,超文本传输协议。HTTP 是一个基于“请求与相应” 模式的、无状态的应用层协议。
HTTP协议对应资源的操作
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的相应消息报告,即获取该资源的头信息 |
POST | 请求向URL位置的资源后附加新的数据 |
PUT | 请求向URL位置存储一个资源,覆盖原URL位置的资源 |
PARCH | 请求局部更新URL位置的资源,即改变该资源的部分内容 |
DELETE | 请求删除URL位置存储的资源。 |
requests的 **kwarges:控制访问的参数(均可选):
参数 | 介绍 |
---|---|
params | 参数 参与url编译 |
data | 放在 data域中 ,字典、字节序列或文件,Request的内容 |
json | 以json 的格式传数据 |
headers | 设置请求头 |
cookies | 设置请求cookies |
auth | 身份验证 |
files | 传文件 |
timeout | 设置请求超时时间 |
proxies | 设置代理 |
allow_redirects | 允许重定向 控制参数 |
stream | 是否是流的形式 控制参数 |
verify | 验证 控制参数 |
cert | 证书 |
具体参数表
方法 | 介绍 |
---|---|
requests.get(url,params=None,**kwarges) | 12 个控制访问的参数 |
requests.head(url,**kwarges) | 13个控制访问参数 |
requests.post(url,data=None,json=None,**kwarges) | 11个控制访问的参数 |
requests.put(url,data=None,**kwarges) | 12个控制访问的参数 |
requests.patch(url,data=None,**kwarges) | 12个控制访问的参数 |
requests.delete(url,**kwarges) | 13个控制访问的参数 |
单元2:爬虫的盗亦有道
网络爬虫的限制
- 来源审查:判断User-Agent进行限制
检查来访HTTP协议头的User-Agent域,只响应浏览器或友好爬虫的访问。 - 发布公告:Robots协议
告知所有爬虫网站的爬取策略,要求爬虫遵守。
Robots协议的使用
网络爬虫:自动或人工识别robots.txt再进行内容爬取。
约束性:Robots协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险。
对Robots协议的理解
类人类行为可不参考Robots 协议
爬取网页玩转网页 | 爬取网站,爬取系列网站 | 爬取全网 |
---|---|---|
访问量很小:可以遵守 范文量较大:建议遵守 | 分商业且偶然:建议遵守 商业利益:必须遵守 | 必须遵守 |
User-agent: *
Disallow:/
Robots协议基本语法
禁止爬虫
单元3 Requests爬虫实战
jd爬虫代码
import requests
url = "https://item.jd.com/2967929.html"
try:
r= requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])# 输出0-1000
except:
print("爬取失败")
amazon
import requests
url = "https://www.amazon.cn/gp/product/B01M8L5z3Y"
try:
kv={ 'user-agent':'Mozilla/5.0'}# 设置头信息
r = requests.get(url,headers=kv)
r.raise_for_status()
r.encoding = r.apparent_enncoding
print(r.text[1000,2000])
except:
print("爬取失败")
百度搜索
import requests
keyword= "Python"
url = "https://baidu.com/s"
try:
k = {'wd':keyword}
kv={ 'user-agent':'Mozilla/5.0'}# 设置头信息
r = requests.get(url,params=k,header=kv)
r.raise_for_status()
r.encoding = r.apparent_enncoding
print(len(r.text))
except:
print("爬取失败")
爬取图片并写入文件
import requests
path = "D:/abc.jpg"
url = "http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
r = requests.get(url)
r.status_code
with open(path, 'wb') as f:
f.write(r.content)
ip地址查询代码
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
r = requests.get(url +'202.204.80.112')
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[-500:])
except:
print("爬取失败")
单元4 BeautifulSoup学习
美味汤
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data</p>','html.parser')
beautiful Soup 库解释器
解析器 | 使用方法 | 条件 |
---|---|---|
bs4的HTML解析器 | BeautifulSoup(mk,‘html.parser’) | 安装bs4库 |
lxml的HTML解析器 | BeautifulSoup(mk, ‘lxml’) | pip install lxml |
lxml的XML解析器 | BeautifulSoup(mk, ‘xml’) | pip install lxml |
html5lib的解析器 | BeautifulSoup(mk, ‘html5lib’) | pip install html5lib |
BeautifulSoup 库的理解
属性 | 说明 |
---|---|
.name | 获取标签的名称 拿上边的代码举例例如 soup.p.name 得到p |
.tag | 获取标签tag 即soup.p 得到<p>data</p> |
.attrs | 获取非属性字符串 soup.p.attrs 得到 { } |
标签树的下行遍历
属性 | 说明 |
---|---|
.contents | 子节点列表,将<tag> 所有儿子节点存入列表 |
.children | 字节点的迭代类型,与.contents 类似,用于循环遍历儿子节点 |
.descendants | 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历 |
标签树的上行遍历
属性 | 说明 |
---|---|
.parent | 获取当前节点的父节点 |
.parents | 获取父节点的列表 在for中使用 |
标签树的平行遍历
属性 | 说明 |
---|---|
.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 |
.previous_sibiling | 返回按照HTML文本顺序的上一个平行节点标签 |
.next_siblings | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 在for中使用 |
.previous_sibilings | 迭代类型,返回按照HTML文本顺序的前序所有平行节点标签 在for中使用 |
bs4 库的prettify()方法
返回格式化的html 代码 加了许多\n
和空格标签
单元5 信息标记
标记后的信息可形成信息组织结构,增加了信息维度
标记后的信息可用于通信、存储或展示
标记的结构与信息一样具有重要价值
标记后的信息更利于程序理解和运用
三种信息标记形式的的比较
名称 | 好处 | 用途 |
---|---|---|
XML | 最早的通信信息标记语言,可扩展性好,但繁琐。 | Internet 上的信息交互与传递 |
JSON | 信息有类型,适合程序处理(js),较XML简洁。 | 移动应用云端和节点的信息通信,无注释。 |
YAML | 信息无类型,文本信息比例最高,可读性好。 | 各类系统的配置文件,有注释易读。 |
信息提取的一般方法:
方法一: 完整解析信息的标记形式,再提取关键信息。
XML JSON YAML
需要标记解析器 例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取过程繁琐,速度慢。
方法二: 搜索式查考信息
<>.find_all(name,attrs,recursive,string,**kwargs)
返回一个列表类型,存储查找的结果。
name:对标签名称的检索字符串。
attrs:对标签属性值的检索字符串,可标注属性检索。
recursive:随否对子孙全部检索,默认是True
string:<>…</> 中字符串区域的检索字符串。
扩展方法
方法 | 说明 |
---|---|
<>.find() | 搜索且只返回一个结果,字符串类型,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,列表类型 |
<>.find_parent() | 在先辈节点中返回一个结果,字符串类型 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型,同.find_all() |
<>.find_next_sibling() | 在后续点中返回一个结果,字符串类型 |
<>.find_previous_siblings() | 在前序平行节点中搜索,返回列表类型,同.find_all() |
<>.find_previous_sibling() | 在前序节点中返回一个结果,字符串类型 |
单元6 爬中国大学排名
程序的结构设计
步骤1 : 从网络上获取大学排名网页内容getHTMLText()
步骤2 : 提取网页内容中信息到合适的数据结构fillUnivList()
步骤3 :利用数据结构展示并输出结果printUnivList()
代码
#!/usr/bin/python3
import requests
from bs4 import BeautifulSoup
import bs4
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[3].string])
pass
def printUnivList(uList,num):
tple = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tple.format("排名", "学校", "分数",chr(12288)))
for i in range(num):
u = uList[i]
print(tple.format(u[0], u[1], u[2],chr(12288)))
def main():
uinfo =[]
url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo,20)
if __name__ == '__main__':
main()
中文对齐问题的解决
采用中文字符的空格填充 chr(12288)
format 详解
^
, <
, >
分别是居中、左对齐、右对齐,后面带宽度, : 号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。
+
表示在正数前显示 +
,负数前显示 -
; (空格)表示在正数前加空格
b
、d
、o
、x
分别是二进制、十进制、八进制、十六进制。
解释
因此tple = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tple.format("排名", "学校", "分数",chr(12288)))
位置 | 解释 |
---|---|
{0:^10}第一个位置 | 居中占10格 |
{1:{3}^10}第二个位置 | 居中 空格部分用 第四个位置上的中文空格代替 |
{2:^10}第三个位置 | 居中占10格 |
单元7 正则表达式
正则表达式 是用来简洁表达一组字符串的表达式。
函数 | 说明 |
---|---|
re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
re.search(pattern,string,flags = 0)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象。
pattern:正则表达式的字符串或原生字符串表示
string:待匹配字符串
flags: 曾泽表达式使用时的控制标记
常用标记 | 说明 |
---|---|
re.I re.IGNORECASE | 忽略正则表达式的大小写,[A-Z]能够匹配小写字符 |
re.M re.MULTILINE | 正则表达式中的^ 操作符能够将给定字符串的每行当作匹配开始 |
re.S re.DOTALL | 正则表示中的. 操作符能匹配所有字符,默认匹配除换行符外的所有字符 |
正则表达式的表示类型
- raw string 类型 原生字符串类型 raw string是不包含对转义符再次转义的字符串;
- string 类型,更繁琐
re库的另一种等价用法
函数 | 说明 |
---|---|
regex.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
regex.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
regex.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
regex.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
regex.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
regex.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
Match 对象的属性
属性 | 说明 |
---|---|
.string | 待匹配文本 |
.re | 匹配时使用的pattern对象(正则表达式) 被compile 编译过的 |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
Match 对象的方法
属性 | 说明 |
---|---|
.group(0) | 获得匹配后的字符串 |
.start() | 匹配字符串在原始字符串的开始位置 |
.end() | 匹配字符串在原始字符串的结束位置 |
.span() | 返回(.start(),.end()) |
列表 [ ‘ss’,‘aaa’]
元组 (‘aaa’,) 类似列表一旦创建不可更改
字典 { ‘a’:‘123’} 键值对
集合{‘aa’,‘vv’} 不可重复
贪婪匹配
Re库默认采用贪婪匹配,即输出匹配最长的子串
最小匹配 ?
最小匹配操作符
操作符 | 说明 |
---|---|
*? | 前一个字符串 0次或无限次扩展,最小匹配 |
+? | 前一个字符串 1次或无限次扩展,最小匹配 |
?? | 前一个字符串 0 次或4次扩展,最小匹配 |
{m,n}? | 前一个字符串 m次至 n次扩展,最小匹配 |
re 到 regex 的转换
regex = re.compile()
单元10 Scrapy框架
Scrapy爬虫框架结构
“5+2” 结构
5个模块和2个中间件
模块解释
模块 | 解释 |
---|---|
SPIDERS | 解析Downloader 返回的响应(Response) 产生爬取项(scraped item) 产生额外的爬取请求(request) |
ENGINE | 不需要用户修改 控制所有模块之间的数据流,根据条件触发事件 |
SCHEDULER | 不需要用户修改 对所有爬取进行管理调度 |
DOWNLOADER | 根据请求下载页面不需要用户修改 |
ITEM PIPELINES | 以流水线方式处理Spider产生的爬取项。 由一组操作顺序组成,类似流水线,每一个操作是一个Item Pipeline 类型 |
Downloader Middleware | 实施Engine \Scheduler 和 Downloader 之间进行 用户可配置的控制 |
Spider Middleware | 对请求和爬取项再处理 |
requests vs. Scrapy
requests | Scrapy |
---|---|
页面级爬虫 | 网站级爬虫 |
功能库 | 框架 |
并发性考虑不足,性能较差 | 并发性好,性能较高 |
重点在于页面下载 | 重点在于爬虫结构 |
定制灵活 | 一般定制灵活,深度定制困难 |
上手十分简单 | 入门稍难 |
Scrapy 命令行格式
scrapy <command> [options] [args]
Scrapy 常用命令
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject <name> [dir] |
genspider | 创建一个爬虫 | scrapy genspider []options<name><domain> |
settings | 获得爬虫的配置信息 | scrapy setting [options] |
crawl | 运行一个爬虫 | scrapy crawl <spider> |
list | 列出工程中的所有爬虫 | scrapy list |
shell | 启动URL 命令行 | scrapy shell [url] |
单元10 Scrapy 爬虫基本使用
parse() 用于处理响应Response,解析内容形成字典发现新的URL 爬取请求。
# -*- coding: utf-8 -*-
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
allowed_domains = ['python123.io']
start_urls = ['http://python123.io/ws/demo.html']
def parse(self, response):
pass
yield 关键字
yield 生成器
生成器是一个不断产生值得函数
包含yield 语句的函数是一个 生成器
生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值,不用预先计算出结果根据现有的值进行计算并返回。
def fen(n):
for i in range(n):
yield i**2
# 反回 1 - n 数的平方 每次执行后返回一下 ,然后直接打印即可
例如下面的例子 不需要创建 ls 列表 节省内存
生成器的优势
- 更节省存储空间
- 相应更灵活
- 使用更灵活
Request类
属性或方法 | 说明 |
---|---|
.url | |
.method | 对应的请求方法 ‘GET’,“POST” 等 |
.headers | 字典类型风格的请求头 |
.body | 请求主体,字符串类型 |
.meta | 用户添加的扩展信息,在Scrapy 内部模块之间传递信息使用 |
.copy() | 复制该请求 |
Response 类型
属性或方法 | 说明 |
---|---|
.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类似字典类型,可以按照字典类型操作
Scrapy爬虫直接提起信息的方法
Scrapy 爬虫支持多种HTML信息提取方法 - Beautiful Soup
- lxml
- re
- Xpath Selector
- CSS Selector
CSS Selector 的基本使用
<HTML>.css('a::attr(href)').extract()
单元12 股票爬虫