定向网络数据爬取和网页解析
Requests库:自动爬取HTML页面,自动网络请求提交
robots.txt:网络爬虫排除标准
Beautiful Soup:解析HTML界面
Re库:正则表达式库,提取页面关键信息
Scrapy*:网络爬虫原理介绍,专业爬虫框架介绍
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.request(method,url,**kwargs)
method:请求方式GET、HEAD、POST、PUT、PATCH、delete、OPTIONS
**kwargs:控制访问的参数,作为参数增加到url中
params:字典或字节序列,作为参数增加到url中
import requests
kv={'key1':'value1','key2':'value2'}
r=requests.request('GET','http://python123.io/ws',params=kv)
print(r.url)
data :字典、字节序列或文件对象,作为Request的内容
import requests
kv={'key1':'value1','key2':'value2'}
r=requests.request('POST','http://python123.io/ws',data=kv)
json:json格式的数据,作为Request的内容
headers:字典,http的定制头#可以模拟任何浏览器
import requests
hd={'user-agent':'Chrome/10'}
r=requests.request('POST','http://python123.io/ws',headers=hd)
cookies:字典或CookieJar,Requests中的cookie
auth:元组类型,支持HTTP认证功能
files:字典类型,传输文件
import requests
fs={'file':open('data.xls','rb')}
r=requests.request('POST','http://python123.io/ws',files=fs)
timeout:超时时间,以秒为单位
r=requests.request('GET','http://python123.io/ws',timeout=30)
proxies:字典类型,设定访问代理服务器,可以增加登录认证
import requests
pxs={'http':'http://user:pass@10.10.10.1:1234',\
'https':'http://10.10.10.1:4321'}
r=requests.request('GET','http://www.baidu.com',proxies=pxs)
allow_redirects:True/False,默认是True,重定向开关
stream:True/False,默认是True,获取内容立即下载开关
verify: True/False,默认是True,认证SSL证书开关
cert:本地SSL证书路径
r=requests.get(url)#构造一个向服务器请求资源的request对象,返回一个包含服务器资源的response对象,最重要的。返回爬虫需要的内容
requests.get(url,params,**kwargs)#url:拟获取页面的链接;params:url的额外参数,字典或字节流样式,可选;**kwargs:12个控制访问参数
import requests
r=requests.get(“http://www.baidu.com”)
print(r.status_code)#返回状态码,如果是200,成功,如果不是200,失败
r.header #返回get请求界面的头部信息,字典类型
Response对象的属性:
r.status_code #HTTP请求的返回状态,200表示连接成功,404表示失败
r.text #http相应内容字符串的信息,即,url对应的页面内容
r.encoding #从http headers中猜测的响应内容的编码方式
r.apparent_encoding #从内容中分析出的响应内容编码方式(备选编码方式)
r.content #http响应内容的二进制形式
Requests的异常处理
requests.ConnectionError #网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPError #HTTP错误异常
requests.URLRequired #URL缺失异常
requests.TooManyRedirects #超过最大重定向次数,产生重定向异常
requests.ConnectionTimeout #连接远程服务超时异常
requests.Timeout #请求URL超时,产生超时异常
r.raise_for_status() #如果不是200,产生异常requests.HTTPErrorr
提交数据代码
import requests
payload={'key1':'value1','key2':'value2'}
r=requests.post('http://httpbin.org/post',data=payload)
print(r.text)
HTTP协议:超文本传输协议,请求-响应,无状态
http://host[:port][path]
host:合法的Internet主机域名或者是IP地址
port:端口号,缺省端口号是80
path:请求资源的路径
方法:
GET:请求获取URL位置的资源
HEAD:请求获取URL位置资源的响应消息报告,即头部信息
POST:请求向URL位置的资源后附加新的数据
PUT:请求向URL位置存储一个资源,覆盖原URL位置的资源
PATCH:请求局部更新URL位置的资源,即改变该处资源的部分内容
DELETE:请求删除URL位置储存的资源
小规模、爬取网页用Requests库,对爬取速度不敏感
中规模、爬取系列网站使用Scrapy库,对爬取速度敏感
大规模、爬取全网、建立搜索引擎,定制开发,爬取全网
网络爬虫的限制:来源审查:判断User-Agent进行限制,发布公告
获取url内容
import requests
try:
hd={'user-agent':'Chrome/10'}
url="https://www.baidu.com"
r=requests.get(url,headers=hd)
r.raise_for_status()
print(r.text[:1000])
except:
print("爬虫失败")
查询IP地址的归属
import requests
try:
ip='112.38.203.59'
hd={'user-agent':'Chrome/10'}
url="https://www.ip138.com/iplookup.asp"
kv={'ip':ip,'action':2}
r=requests.get(url,headers=hd,params=kv)
r.raise_for_status()
r.encoding=r.apparent_encoding
print(r.url+'\n',r.text[:1000])
except:
print("爬虫失败")
解析网站信息
import requests
from bs4 import BeautifulSoup
r=requests.get(url)
demo=r.text
soup=BeautifulSoup(demo,’html.parse’)
BeautifulSoup库解析器
bs4的HTML解析器:BeautifulSoup(mk,’html.parse’),条件是安装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的基本元素
Tag:标签<></>
Name:标签的名字
……
,p是标签的名字,.nameAttributes:标签的属性,字典形式组织,格式:.attrs
Navigablestring:标签内,非属性的字符串
Comment:标签内字符串的注释部分,一种特殊的Comment类型
soup.a后面可以点的东西:parent上一层标签,name名字,string里面的字符串,attrs属性
<!注释部分>
标签树的下行遍历
.contents子节点的列表,将所有的儿子存入列表
.children子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
标签树的上行遍历
.parent节点的父亲标签
.parents节点先辈标签的迭代类型,用于循环遍历先辈节点
标签树的平行遍历
.next_sibling按照HTML文本顺序的下一个平行节点标签
.previous_sibling按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
. previous _siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签
迭代类型智能在for in类型遍历
print(soup.prettify())在每个标签后加一个’\n’,显得好看点,也可以对单个标签进行处理
信息的三种标识:XML,JSON,YAML
XML标识形式:,,
JSON标识形式:键值对,’key’:’value’,’key’:[‘value1’,’value2’],’key1’:{‘key2’:’value’}
YAML标识形式:
key:value
key :#Comment
-value1
-value2
key:
subkey:subvalue
XML:互联网上的信息交换和传递
JSON:移动应用云端和节点的信息通信,无注释
YAML:各类系统的配置文件,有注释易读
信息提取的一般方法
方法1:完整解析信息的标记形式,在提取关键信息
XML JSON YAML
需要标记解析器,比如果bs4的标签树遍历,信息解析准确,但是速度慢
方法2:无视标记形式,直接搜索关键信息
对信息的文本查找函数即可,提取速度快,但是准确性不好
soup的函数
soup.find_all(‘a’)#查找soup中所有的a标签
soup.find_all([‘a’,’b’])#查找soup中所有的a,b标签
soup.find_all(True)#返回soup中的所有标签
soup.find_all(re.compile(‘b’))#显示所有以b开头的标签,re是正则表达式库
soup.find_all(‘p’,’course’)#显示所有带有course的p标签
soup.find_all(id=’link1’)#返回属性中id=‘link1’的标签元素
soup.find_all(id=re.compile(‘link’))#返回id=以link开头的标签
soup.find_all(string=’basic python’)#查找basic python字符串
Ssoup.find_all(string=re.compile(basic python))#查找出现python的字符串
soup.a.get(‘href’)#返回标签a中的所有href内容
<>.find.all(name,attrs,recursive,string,**kwargs),<>表示一个节点
返回一个列表类型,储存查找的结果
name:对标签名称的检索字符串
attrs:对标签属性值的检索字符串,可标注属性检索
recursive:是否对子孙全部检索,默认为True
string:查找字符串
(…)等价于.find_all(…)
soup(…)等价于soup.find_all(…)
扩展方法
<>.find()#搜索且只返回一个结果,字符串类型,同find_all()参数
<>.findparents()#在先辈节点中搜索,返回列表
<>.findparent()#在父亲节点中返回一个结果,字符串类型
<>.find_nextsiblings()#在后续平行节点中搜索,返回列表
<>.find_nextsibling()#在后续节点中搜索,返回一个结果,字符串
<>.find_previous_siblings()#在前序平行节点中搜索,返回列表
<>.find_nextsibling()#在前序节点中搜索,返回一个结果,字符串
************************************************************************************************
``
正则表达式:通用的字符串表达框架,简洁表达一组字符串的表达式,简洁+特征
PN/PYN/PYTN/PYTHN/PYTHON的正则表达式:P(Y|YT|YTH|YTHO)?N
PY/PYY/PYYY/……/PYYYY…的正则表达式:PY+
PY开头,后续不多于是个字符,后续字符不能是P/Y,PY[^PY](0,10)
应用:表达文本类型的特征(病毒,入侵),同时查找或者替换一组字符串,匹配字符串的全部或者部分,主要应用在字符串匹配中
正则表达式的使用:
编译:将符合正则表达式语法的字符串转换成正则表达式特征
正则表达式是由字符和操作符构成的
. #表示任何单个字符
[] #字符集,对单个字符给出取值范围,[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_]
经典表示方法
^{A-Za-z}+$表示26个字母表示的字符串
^{A-Za-z0-9}+&由26个字母和数字表示的字符串
^-?\d+$表示整数形式的字符串
^[0-9]*[1-9][0-9]*$ 表示正整数字符串
[1-9]\d{5}中国境内邮政编码,6位
[\u4e00-\u9fa5] 匹配中文字符串
ip地址 0-99:[1-9]?\d,100-199:1\d{2},200-249:2{0-4}\d,250-255:25[0-5]
Re的基本使用
正则表达式的表示类型
原生字符串,raw string,不把‘\’作为注释,表示为 r’text’,如r’[1-9]\d{5}’,当正则表达式包含转义符的时候使用raw string
re库的功能函数
re.search() #在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()#在一个字符串的开始位置匹配正则表达式,返回match对象
re.findall()#搜索字符串,以列表的形式返回全部匹配的字符串
re.split(pattern,string,maxsplit=0,flags=0)#将一个字符串按照正则表达式匹配结果进行分割,返回列表类型,maxsplit最大分割数,剩余部分作为最后一个元素输出
re.finditer()#搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象,if match: print(match.group(0))
re.sub(pattern,repl,string,count=0,flags=0)#在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串,repl替换匹配正则表达式的字符串,count匹配的最大替换数
re.search(pattern,string,flags=0)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
pattern是正则表达式的字符串或原生字符串表示
string是带匹配的字符串
flags是正则表达式使用时的控制标记,re.I IGNORECASE忽略正则表达式的大小写,[A-Z]能匹配小写字符;re.M re.MULTILINE正则表达式中的^操作符能够将给定的字符串的每行当做匹配开始;re.S re.DOTALL 正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符, match=re.search(r'[1-9]\d{5}','BIT 100081'),match.group(0)输出匹配的字符串
rst=re.search(r’[1-9]\d{5}’,’BIT100001’)#函数式用法,一次性操作
pat=re.compile(r’[1-9]\d{5}’);rst=pat.search(‘BIT100001’)#面向对象用法,编译后多次操作,加快程序的运行
Re库的match对象及其属性
.string#待匹配的文本
.re#匹配是使用的pattern对象(正则表达式)
.pos#正则表达式搜索文本的开始位置
.endpos#正则表达式搜索文本的结束位置
方法
.group(0)#获得匹配后的字符串
.start()#匹配字符串在原始字符串的开始位置
.end()#匹配字符串在原始字符串的结束位置
.span#返回(.start(),.end())
Re库的贪婪匹配和最小匹配
Re库默认采用贪婪匹配,即输出匹配最长的子串,match.group(0)就是输出最长的子串
match=re.search(r‘PY.*?N’,’PYANBNCNDN’);match.group(0);就是输出最小的字符串,区别在于?
最小匹配操作符
*? #前一个字符0次或无限次扩展,最小匹配、
+? #前一个字符1次或无限次扩展,最小匹配
?? #前一个字符0次或1次扩展,最小匹配
{m,m}? #扩展前一个字符m至n次(含n),最小匹配
pat_price=re.compile(r'\"view_price\"\:\"[\d\.]*\"')#匹配并返回”view_price”:数字类型的字符串
pat_name=re.compile(r'\"view_title\"\:\".*?\"')
pat_price.findall('"view_price":"119.00"')
pat_name.findall('"view_title":"裤子"')
返回:['"view_price":"119.00"'],列表类型
['"view_title":"裤子"'], 列表类型
scrapy框架,功能强大的网络爬虫框架,“5+2结构”
ENGINE、SPIDERS、DOWNLOADER、ITEM PIPELENS、SCHEDULER模块
scrapy常用命令:
startproject 常见一个新工程 scrapy startproject <name> [dir]
genspider 创建一个爬虫 scrapy genspider [opitions]<name>[domain]
settings 获取爬虫的配置信息 scrapy settings [opitions]
crawl 运行一个爬虫 scrapy crawl <spider>
list 列出工程中所有的爬虫 scrapy list
shell 启动URL调试命令行 scrapy shell [url]
产生步骤
步骤1:创建一个爬虫工程scrapy startproject python123demo
步骤2:在工程中产生一个爬虫 scrapy genspider demo python123.io
步骤3:配置产生的spider爬虫,更改demo.py文件
步骤4:运行爬虫,获取网页scrapy crawl demo
scrapy爬虫的使用步骤
步骤1:创建一个工程和spider模板
步骤2:编写spider
步骤3:编写Item Pipelines
步骤4:优化配置策略
yield关键字
yield-生成器
生成器是不断产生值的函数
包含yield语句的函数是一个生成器
生成器每次运行的时候回产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值
例子:
def gen(n):
for i in range(n):
yield i**2
for i in gen(5):
print(i,' ',end='')
0 1 4 9 16
生成器就是生成一些数据,可以在生成器中遍历这些数据
生成器更节省储存空间,响应更迅速,使用更灵活
scrapy数据类型
Requsts类
Response类
Item类
Requests类
class scrapy.http.requests()
Request对象表示一个HTTP请求
由Spider生成,由Downloder执行
属性和方法
.url Response对应的请求URL地址
.method 对应请求的方法,‘GET‘’POST’等
.headers 字典类型风格的请求头
.body 请求内容的主体,字符串类型
.meta 用户添加的扩展信息,在Scrapy内部模块间传递信息使用
.copy() 复制该请求
Response类
class scrapy.http.Response()
Response对象表示一个http响应
用Downloader形成,由Spider处理
属性和方法
.url .headers .body .copy()
.status 状态码,默认是200(表示成功)
.flags一组标记
.request 产生Response类型对应的Requests对象
Item类
class scrapy.item.Item()
Item对象表示一个从HTML页面中提取的信息内容
由Spider生成,由Item Pipelines处理
Item类型类似字典类型,可以按照字典类型操作
Scrapy爬虫支持多种HTML信息提取方法
BeautifulSoup
lxml
re
XPath Selector
CSS Selector
CSS Selector使用方法
<HTML>.css(‘a::attr(href)’).extract()#a是标签名称,href是标签属性++
setting.py文件
CONCYRRENT_REQUESTS表示Downloade最大并发请求下载数量,默认32
CONCURRENT_ITEMS表示Item Pipelines最大并发ITEM处理数量,默认100
CONCURRENT_REQUESTS_PER_DOMAIN每个目标域名最大的开发请求数量,默认8
CONCURRENT_REQUESTS_PER_IP每个目标IP最大的并发请求数量,默认0,非0有效