目录
python网络爬虫与信息提取
Requests库入门
HTTP协议及Requests库方法
Requests库的get()方法
Requests库的安装
Requests库主要方法解析
爬取网页的通用代码框架
Robots协议
Robots协议的遵守方式
requests库网络爬虫实战五个实例
实例1:京东商品页面的爬取
实例2:亚马逊商品页面的爬取
实例3:百度360搜索关键词提交
实例4:网络图片的爬取与储存
实例5:IP地址归属地的自动查询
Beautiful Soup库入门
Beautiful Soup库安装
Beautiful Soup库的基本元素
基于bs4库的HTML内容遍历方法
基于bs4库的HTML格式输出
信息组织与提取方法
信息标记得到三种形式
三种信息标记形式的比较
信息提取的一般方法
基于bs4库的HTML内容查找方法
扩展方法
实例:中国大学排名爬虫
中国大学排名定向爬虫介绍
中国大学排名定向爬虫编写
「中国大学排名定向爬虫」实例优化
Re(正则表达式)库入门
正则表达式的概念
正则表达式的语法
Re库的基本使用
Re库的Match对象
Re库的贪婪匹配和最小匹配
实例2:淘宝商品比价定向爬虫
「淘宝商品比价定向爬虫」实例介绍
程序的结构设计
「淘宝商品比价定向爬虫」实例编写
实例3:股票数据定向爬虫
「股票数据定向爬虫」实例介绍
「股票数据定向爬虫」实例编写
「股票数据定向爬虫」实例优化
Scrapy爬虫框架
Scrapy爬虫框架介绍
Scrapy爬虫框架解析
requests库和Scrapy爬虫的比较
Scrapy爬虫的常用命令
Scrapy爬虫的基本使用
Scrapy爬虫的第一个实例
yield关键字的使用
Scrapy爬虫的基本使用
实例4:股票数据Scrapy爬虫
「股票数据Scrapy爬虫」实例介绍
「股票数据Scrapy爬虫」实例编写
python网络爬虫与信息提取
Requests库入门
HTTP协议及Requests库方法
HTTP协议及Requests库方法
requests库的七个主要方法
request.request() #构建一个请求,支撑以下各方法的基础方法 request.get() #获取HTML网页的主要方法,对应于HTTP的GET request.head() #获取HTML网页头信息的方法,对应于HTTP的HEAD request.post() #向HTML网页提交POST请求的方法,对应于HTTP的POST request.put() #向HTML网页提交PUT请求的方法,对应于HTTP的PUT request.patch() #向HTML网页提交局部修改请求,对应于HTTP的PATCH request.delete()#向HTML页面提交删除请求,对应于HTTP的Delete
HTTP协议
HTTP,超文本传输协议。
HTTP是一个基于「请求与响应」模式的、无状态的应用层协议。
HTTP协议采用URL作为定位网络资源的标识。
URL格式 http://host:port
host:合法的internet主机域名或IP地址
port:端口号,缺省端口为80
path:请求资源的路径
HTTP URL的理解:
URL是通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源。
HTTP协议对资源的操作
GET #请求获取URL位置的资源 HEAD #请求获取URL位子资源的响应消息报告,即获得该资源的头部信息 POST #请求向URL位子的资源后附加新的数据 PUT #请求向URL位置存储一个资源,覆盖原URL位置的资源 PATCH #请求局部更新URL位置的资源,即改变该处资源的部分内容 DELETE #请求删除URL位置存储的资源
理解PATHC和PUT的区别
假设URL位置有一组数据UserInfo,包括UserID、UserName等20个字段。
需求:用户改变了UserName,其他不变。
*采用PATCH,仅向URL提交UserName的局部更新请求。
*采用PUT,必须将所有20个字段一并提交到URL,未提交字段被删除
PATCH的主要好处:节省网络带宽
Requests库的get()方法
r = requests.get(url) #构造一个向服务器请求资源的Request对象,返回一个包含服务器资源的Response对象
#requests.get(url,params=None,**kwargs)
#url:获取页面的URL连接
#params:url中的额外参数,字典或字节流格式,可选
#**kwargs:12个控制访问的参数,可选
response对象的属性
r.status_code #HTTP请求的返回状态,200表示连接成功,404表示失败(只要不是200都是失败) r.text #HTTP响应内容的字符串形式,即,url对应的页面内容 r.encoding#从HTTP header中猜测的响应内容编码方式 r.apparent_encoding#从内容中分析出的响应内容编码方式(备选编码方式) r.content #HTTP响应内容的二进制形式
r.encoding:如果header中不存在charset,则认为编码为ISO-8859-1
r.apparent_encoding:根据网页内容分析出的编码方式
当r.encoding显示乱码时,使用r.apparent_encoding来解码相关信息。
Requests库的安装
pip install requests
Requests库主要方法解析
request.request(method,url,**kwargs)
method:请求方式,对应get/put/post等七种方法
url:获取页面的url链接
**kwargs:控制访问的参数,共13个
#method:请求方式
r=requests.request('GET',url,**kwargs)
r=requests.request('HEAD',url,**kwargs)
r=requests.request('POST',url,**kwargs)
r=requests.request('PUT',url,**kwargs)
r=requests.request('PATCH',url,**kwargs)
r=requests.request('delete',url,**kwargs)
r=requests.request('OPTIONS',url,**kwargs) #获取服务器与客户端可以打交道的参数
r=requests.request(method,url,**kwargs) #**kwargs:控制访问的参数,均为可选项
params
params:字典或字节序列,作为参数增加到url中
例:
kv = {'key1':'value1','key2':'value2'} r = requests.request('GET',url,params=kv) print(r.url) 返回:url?key1=value1&key2=value2
data
data:字典、字节序列或文件对象,作为request的内容
例:
kv = {'key1':'value1','key2':'value2'} r = requests.request('POST',url,data=kv) body = '主体内容' r = requests.request('POST',url,data=body)
json
json:JSON格式的数据,作为request的内容
例:
kv = {'key1':'value1','key2':'value2'} r = requests.request('POST',url,json=kv)
headers
headers:字典,HTTP定制头
可以模拟任何想模拟的浏览器向服务器发起访问
例:
hd={'user-agent':'chrome/10'}
r = requests.request('POST',url,headers=hd)
cookies
cookies:字典或cookieJar,Request中的cookie
auth
auth:元组,支持HTTP认证功能
files
files:字典类型,传输文件
可以向某个特定的链接提交文件
例:
fs = {'file':open('data.xls','rb')}
r = requests.request('POST',url,files=fs)
timeout
timeout:设定超时时间,秒为单位
在请求时间内没有返回回来,那么会产生一个timeout异常
例:
r = requests.request('GET',url,timeout=10)
proxies
proxies:字典类型,设定访问代理服务器,可以增加登录认证
可以有效隐藏爬取网页的源IP地址信息
例:
pxs = {'http':'url' ,'https':'url2'}
r = requests.request('GET',url,proxies=pxs)
allow_redirects,stream,verify,cert
allow_redirects: True/False,默认为True,重定向开关
stream:True/False,默认为True,获取内容立即下载开关
verify:True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径
爬取网页的通用代码框架
try:
r = requests.get(url,timeout=30)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
#网络连接有风险,异常处理很重要
理解requests库的异常
requests.ConnectionError:网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPError:HTTP错误异常
requests.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,将产生一次异常
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__=="__main__":
url= 'http://www.baidu.com'
print(getHTMLText(url))
Robots协议
Robots协议:网络爬虫排除协议
作用:网站告知爬虫哪些页面可以抓取,哪些不行。
形式:在网站根目录下的robots.txt文件
User-agent:* :任何爬虫
Disallow:/? :不允许访问以问号开头的路径
Robots协议的遵守方式
网络爬虫:自动或人工识别robots.txt,再进行内容爬取。
约束性:Robots协议是建议但非约束性,网络爬虫可以不遵守,但存在法律风险。
类人行为可不参考robots协议
requests库网络爬虫实战五个实例
实例1:京东商品页面的爬取
import requests
url = "https://item.jd.con/2967929.html"
try:
r = requests.get(url,timeout=30)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
实例2:亚马逊商品页面的爬取
import requests
url = "任意亚马逊商品页面"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url,timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
实例3:百度360搜索关键词提交
import requests
keyword = "python"
url = 'http://www.baidu.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
# 360
import requests
keyword = "python"
url = 'http://www.so.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
#弹幕提示pip一个fake_useragent库,避免反扒
实例4:网络图片的爬取与储存
import requests
import os
url ="图片地址"
root = "D://PICS//" #存储地址
path = root = url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,"wb") as f:
f.write(r.content)
f.close()
print("文件保存成功")
except:
print("爬取失败")
#因为反扒原因,爬取失败
实例5:IP地址归属地的自动查询
import requests
url = "IP地址查询网站接口"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url+'想查询的IP地址',timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
Beautiful Soup库入门
Beautiful Soup库安装
import requests
url = "https://item.jd.con/2967929.html"
try:
r = requests.get(url,timeout=30)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
实例2:亚马逊商品页面的爬取
import requests
url = "任意亚马逊商品页面"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url,timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
实例3:百度360搜索关键词提交
import requests
keyword = "python"
url = 'http://www.baidu.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
# 360
import requests
keyword = "python"
url = 'http://www.so.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
#弹幕提示pip一个fake_useragent库,避免反扒
实例4:网络图片的爬取与储存
import requests
import os
url ="图片地址"
root = "D://PICS//" #存储地址
path = root = url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,"wb") as f:
f.write(r.content)
f.close()
print("文件保存成功")
except:
print("爬取失败")
#因为反扒原因,爬取失败
实例5:IP地址归属地的自动查询
import requests
url = "IP地址查询网站接口"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url+'想查询的IP地址',timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
Beautiful Soup库入门
Beautiful Soup库安装
import requests
keyword = "python"
url = 'http://www.baidu.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
# 360
import requests
keyword = "python"
url = 'http://www.so.com/s'
try:
kv = {'wd':keyword}
r = requests.get(url,timeout=30,params=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(len(r.text)
except:
print("产生异常")
#弹幕提示pip一个fake_useragent库,避免反扒
实例4:网络图片的爬取与储存
import requests
import os
url ="图片地址"
root = "D://PICS//" #存储地址
path = root = url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,"wb") as f:
f.write(r.content)
f.close()
print("文件保存成功")
except:
print("爬取失败")
#因为反扒原因,爬取失败
实例5:IP地址归属地的自动查询
import requests
url = "IP地址查询网站接口"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url+'想查询的IP地址',timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
Beautiful Soup库入门
Beautiful Soup库安装
import requests
url = "IP地址查询网站接口"
try:
kv = {'user-agent':'Mozilla/5.0'}
r = requests.get(url+'想查询的IP地址',timeout=30,headers=kv)
r.raise_for_status() #如果状态码不是200,将产生一次异常
r.encoding = r.apparent_encoding
print(r.text)
except:
print("产生异常")
Beautiful Soup库入门
Beautiful Soup库安装
pip install beautifulsoup4
from bs4 import BeautifulSoup
soup = BeautifulSoup('data
','html.parser')
Beautiful Soup库的基本元素
Beautiful Soup库是解析、遍历、维护「标签树」的功能库
Beautiful Soup对应一个HTML/XML文档的全部内容
Beautiful Soup库解析器
bs4的HTML解析器:
语法:BeautifulSoup(mk,'html.parser')
条件:安装bs4库
lxml的HTML解析器:
语法:BeautifulSoup(mk,'lxml')
条件:pip install lxml
lxml的xml解析器:
语法:BeautifulSoup(ml,'xml')
条件:pip install lxml
html5lib的解析器:
语法:BeautifulSoup(mk,'html5lib')
条件:pip install html5lib
BeautifulSoup类的基本元素
Tag:标签,醉基本的信息组织单元,分别用<>和>表明开头和结尾
Name:标签的名字,
...
的名字是'p',格式:Attributes:标签的属性,字典形式组织,格式:
NavigableString:标签内非属性字符串,<>...>中的字符串,格式:
Comment:标签内字符串的注释部分,一种特殊的Comment类型
基于bs4库的HTML内容遍历方法
标签树的下行遍历
.contents :子节点的列表,将
.children :子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants : 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
for child in soup.body.children:
print(child) #遍历儿子节点
for child in soup.body.descendants:
print(child) #遍历子孙节点
标签树的上行遍历
.parent :节点的父亲标签
.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点
from bs4 import BeautifulSoup as bs
soup = bs('123','html.parser')
for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)
标签树的平行遍历
平行遍历发生在同一个父亲节点下的各节点间
.next_sibling:返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling:返回按照HTML文本顺序的上一个平行节点标签
.next_siblings:迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings:迭代类型,返回按照HTML文本顺序的前续所有平行节点标签
for sibling in soup.a.next_siblings:
print(sibling) #遍历后续节点
for sibling in soup.a.previous_siblings:
print(sibling) #遍历前续节点
基于bs4库的HTML格式输出
bs4库的prettify()方法
from bs4 import BeautifulSoup as bs
soup = bs('123','html.parser')
soup.a.string #返回:'123'
print(soup.a.prettify()) #返回123
信息组织与提取方法
信息标记得到三种形式
信息的标记
*标记后的信息可形成信息组织结构,增加了信息维度
*标记后的信息可用于通信、存储或展示
*标记的结构与信息一样具有重要价值
*标记后的信息更利于程序理解和运用
HTML的信息标记
HTML通过预定义的<>……>标签形式组织不同类型的信息
XML
与HTML类似
JOSN
有类型的键值对 "key":"value"
嵌套使用{}
YAML
无类型键值对 key:value
嵌套使用缩进
-表达并列关系
|表达整块数据
#表示注释
例:
name:
-value
-value1
三种信息标记形式的比较
XML:最早的通用信息标记语言,可扩展性好,但繁琐。Internet上的信息交互与传递
JSON:信息有类型,适合程序处理(js),较XML简洁。移动应用云端和节点的信息通信,无注释
YAML:信息无类型,文本信息比例最高,可读性好。各类系统的配置文件,有注释,易读
信息提取的一般方法
方法一:完整解析信息的标记形式,再提取关键信息。
需要标记解释器 例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取过程繁琐,速度慢
方法二:无视标记形式,直接搜索关键信息。
对信息的文本查找函数即可。
优点:提取过程简洁,速度较快
缺点:提取结果准确性与信息内容相关
融合方法:结合形式解析与搜索方法,提取关键信息。
需要标记解析器及文本查找函数。
实例:提取HTML中所有URL链接
思路:1)搜索到所有标签
2)解析标签格式,提取href后的链接内容
from bs4 import BeautifulSoup as bs
import requests
r = requests.get("http://python123.io/ws/demo.html")
demo = r.text
soup = bs(demo,'html.parser')
for link in soup.find_all('a'):
print(link.get('href'))
基于bs4库的HTML内容查找方法
fand_all(name,attrs,recursive,string,**kwargs)
返回一个标签类型,存储查找的结果。
name:对标签名称的检索字符串。
attrs:对标签属性值的检索字符串,可标注属性检索。
recursive:是否对子孙全部检索,默认True。
string:<>……>中字符串区域的检索字符串。
soup(……)等价于soup.find_all(……)
扩展方法
<>.find
搜索且只返回一个结果,字符串类型,同.find_all()参数
<>.find_parents()
在先辈节点中搜索,返回列表类型,
<>.find_parent()
在先辈节点中返回一个结果,字符串类型,
<>.find_nex_siblings()
在后续平行节点中搜索,返回列表类型,
<>.find_next_sibling()
在后续平行节点中返回一个结果,字符串类型,
<>.find_previous_siblings()
在前序平行节点中搜索,返回列表类型,
<>.find_previous_sibling()
在前序平行节点中返回一个结果,字符串类型
实例:中国大学排名爬虫
中国大学排名定向爬虫介绍
功能描述
输入:大学排名URL链接
输出:大学排名信息的屏幕输出(排名,大学名称,总分)
技术路线:requests——bs4
定向爬虫:仅对输入URL进行爬取,不扩展爬取
程序的结构设计
步骤一:从网络上获取大学排名网页内容——getHTMLText()
步骤二:提取网页内容中信息到合适的数据结构——fillUnivList()
步骤三:利用数据结构展示并输出结果——printUnivList()
中国大学排名定向爬虫编写
import requests
from bs4 import BeautifulSoup
import bs4
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
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])
def printUnivList(ulist, num):
print("{:^10}t{:^6}t{:^10}".format("排名","学校名称","总分"))
for i in range(num):
u=ulist[i]
print("{:^10}t{:^6}t{:^10}".format(u[0],u[1],u[2]))
def main():
uinfo = []
url = 'https://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs
main()
「中国大学排名定向爬虫」实例优化
解决了中文输出的问题
import requests
from bs4 import BeautifulSoup
import bs4
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
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])
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 = 'https://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs
main()
Re(正则表达式)库入门
正则表达式的概念
正则表达式是用来简洁表达一组字符串的表达式。
*通用的字符串表达框架
*简洁表达一组字符串的表达式
*针对字符串表达「简洁」和「特征」思想的工具
*判断某字符串的特征归属
正则表达式阿紫文本处理中十分常用
*表达文本类型的特征(病毒、入侵等)
*同时查找或替换一组字符串
*匹配字符串的全部或部分
正则表达式的使用
*编译:将符合正则表达式语法的字符串转换成正则表达式特征。
正则表达式的语法
基础语法
正则表达式语法由字符和操作符构成
.:表示任何单个字符
[]:字符集,对单个字符给出取值范围
[^]:非字符集,对单个字符给出排除范围
*:前一个字符0次或无限次扩展
+:前一个字符1次或无限次扩展
?:前一个字符0次或1次扩展
|:左右表达式任意一个
{m}:扩展前一个字符M次
{m,n}:扩展前一个字符m至n次(含n)
^:匹配字符串开头
$:匹配字符串结尾
():分组标记,内部职能使用|操作符
d:数字,等价于[0-9]
w:单词字符,等价于[A-Za-z0-9_]
正则表达式语法实例
P(Y|YT|YTH|YTHO)?N 对应:'PY'、 'PYN'、 'PYTN'、 'PYTHN '、 'PYTHON'
PYTHON+ 对应:'PYTHON'、'PYTHONN'、'PYTHONNN'
经典正则表达式实例
^[A-Za-z]+$ 由26个字母组成的字符串
^[A-Za-z0-9]+$ 由26个字母和数字组成的字符串
^-?d+$ 整数形式的字符串
^[0-9]*[1-9] [0-9] *$ 正整数形式的字符串
[1-9]d{5} 中国境内邮政编码,6位
[u4e00-u9fa5] 匹配中文字符
d{3}-d{8}|d{4}-d{7} 国内电话号码,010-68913536
Re库的基本使用
Re库是Python的标准库,主要用于字符串匹配
调用方法:import re
正则表达式的表示类型
*raw string类型(原生字符串类型)
re库采用raw string类型表示正则表达式,表示为:r'text'
例如:r'[1-9]d{5}'
raw string是不包含转义符的字符串
*string类型,更繁琐
例如:'[1-9]d{5}'
Re库主要功能函数
re.search(pattern,string,flags=0)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
pattern:正则表达式的字符串或原生字符串表示
string:待匹配的字符串
flags:正则表达式使用时的控制标记
re.match(pattern,string,flags=0)
从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall(pattern,string,flags=0)
搜索字符串,以列表类型返回全部能匹配的子串
re.split(pattern,string,maxsplit=0,flags=0)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
maxsplit:最大分割数,剩余部分作为最后一个元素输出
re.finditer(pattern,string,flags=0)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素都是match对象
re.sub(pattern,repl.string,count=0,flags=0)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
repl:替换匹配字符串的字符串
count:匹配的最大替换次数
flags:正则表达式使用时的控制标记
re.I re.IGNORECASE:忽略正则表达式的大小写,[A-Z]能够匹配小写字符
re.M re.MULTILINE:正则表达式中的^操作符能够将给定字符串的每行当做匹配开始
re.S re.DOTALL:正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符
Re库的另一种等价用法
函数式用法:一次性操作
res = re.search(r'[1-9]d{5}','BIT 100081')
面向对象用法:编译后的多次操作
pat = re.compile(r'[1-9]d{5}')
rst = pat.search('BIT 100081')
re.compile(pattern,flags=0)
将正则表达式的字符串形式编译成正则表达式对象
例:regex = re.compile(r'[1-9]d{5}')
Re库的Match对象
Match对象的属性
.string:待匹配的文本
.re:匹配时使用的pattern对象(正则表达式)
.pos:正则表达式搜索文本的开始位置
.endpos:正则表达式搜索文本的结束位置
Match对象的方法
.group(0):获得匹配后的字符串 #有更多的使用方法
.start():匹配字符串在原始字符串的开始位置
.end():匹配字符串在原始字符串的结束位置
.span():返回(.start(),.end())
Re库的贪婪匹配和最小匹配
实例
match = re.search(r'PY.*n','PYANBNCNDN') match.group(0) #Re库默认采用贪婪匹配,即输出匹配最长的子串。 #最小匹配 match = re.search(r'PY.*?n','PYANBNCNDN') match.group(0)
最小匹配操作符
*?:前一个字符0次或无限次扩展,最小匹配
+?:前一个字符1次或无限次扩展,最小匹配
??:前一个字符0次或1次扩展,最小匹配
{m,n}?:前一个字符M至N次(含n),最小匹配
实例2:淘宝商品比价定向爬虫
「淘宝商品比价定向爬虫」实例介绍
目标:获取淘宝搜索页面的信息,提取其中的商品名称和价格
理解:淘宝的搜索接口,翻页的处理
技术路线:requests-re
https://s.taobao.com/search?q=%E4%B9%A6%E5%8C%85&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.21814703.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306&bcoffset=1&ntoffset=1&p4ppushleft=2%2C48&s=44
程序的结构设计
步骤1:提交商品搜索请求,循环获取页面
步骤2:对于每个页面,提取商品名称和价格信息
步骤3:将信息输出到屏幕上
「淘宝商品比价定向爬虫」实例编写
#CrowTaobaoPrice.py
#由于采用JS渲染,此爬虫已失效,仅供参考
import requests
import re
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def parsePage(ilt, html):
try:
plt = re.findall(r'"view_price":"[d.]*"',html)
tlt = re.findall(r'"raw_title":".*?"',html)
for i in range(len(plt)):
price = eval(plt[i].split(':')[1])
title = eval(tlt[i].split(':')[1])
ilt.append([price , title])
except:
print("")
def printGoodsList(ilt):
tplt = "{:4}t{:8}t{:16}"
print(tplt.format("序号", "价格", "商品名称"))
count = 0
for g in ilt:
count = count + 1
print(tplt.format(count, g[0], g[1]))
def main():
goods = '书包'
depth = 3
start_url = 'https://s.taobao.com/search?q=' + goods
infoList = []
for i in range(depth):
try:
url = start_url + '&s=' + str(44*i)
html = getHTMLText(url)
parsePage(infoList, html)
except:
continue
printGoodsList(infoList)
实例3:股票数据定向爬虫
「股票数据定向爬虫」实例介绍
「股票数据定向爬虫」实例介绍
目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
技术路线:requests-bs4-re
候选数据网站的选择
选取原则:股票信息静态存在于HTML页面中,非JS代码生成,没有Robots协议限制
选取方法:浏览器F12,源代码查看等
选取心态:不要纠结于某个网站,多找信息源尝试
程序的结构设计
步骤1:从东方财富网获取股票列表
步骤2:根据股票列表逐个到百度股票获取个股信息
步骤3:将结果存储到文件
「股票数据定向爬虫」实例编写
#CrawBaiduStocksA.py
#无法适用于JS渲染的页面
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def getStockList(lst, stockURL):
html = getHTMLText(stockURL)
soup = BeautifulSoup(html, 'html.parser')
a = soup.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]d{6}", href)[0])
except:
continue
def getStockInfo(lst, stockURL, fpath):
for stock in lst:
url = stockURL + stock + ".html"
html = getHTMLText(url)
try:
if html=="":
continue
infoDict = {}
soup = BeautifulSoup(html, 'html.parser')
stockInfo = soup.find('div',attrs={'class':'stock-bets'})
name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
infoDict.update({'股票名称': name.text.split()[0]})
keyList = stockInfo.find_all('dt')
valueList = stockInfo.find_all('dd')
for i in range(len(keyList)):
key = keyList[i].text
val = valueList[i].text
infoDict[key] = val
with open(fpath, 'a', encoding='utf-8') as f:
f.write( str(infoDict) + 'n' )
except:
traceback.print_exc()
continue
def main():
stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D:/BaiduStockInfo.txt'
slist=[]
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)
main()
「股票数据定向爬虫」实例优化
#CrawBaiduStocksB.py
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url, code="utf-8"):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = code
return r.text
except:
return ""
def getStockList(lst, stockURL):
html = getHTMLText(stockURL, "GB2312")
soup = BeautifulSoup(html, 'html.parser')
a = soup.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]d{6}", href)[0])
except:
continue
def getStockInfo(lst, stockURL, fpath):
count = 0
for stock in lst:
url = stockURL + stock + ".html"
html = getHTMLText(url)
try:
if html=="":
continue
infoDict = {}
soup = BeautifulSoup(html, 'html.parser')
stockInfo = soup.find('div',attrs={'class':'stock-bets'})
name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
infoDict.update({'股票名称': name.text.split()[0]})
keyList = stockInfo.find_all('dt')
valueList = stockInfo.find_all('dd')
for i in range(len(keyList)):
key = keyList[i].text
val = valueList[i].text
infoDict[key] = val
with open(fpath, 'a', encoding='utf-8') as f:
f.write( str(infoDict) + 'n' )
count = count + 1
print("r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
except:
count = count + 1
print("r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
continue
def main():
stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D:/BaiduStockInfo.txt'
slist=[]
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)
main()
Scrapy爬虫框架
Scrapy爬虫框架介绍
#CrawBaiduStocksB.py
import requests
from bs4 import BeautifulSoup
import traceback
import re
def getHTMLText(url, code="utf-8"):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = code
return r.text
except:
return ""
def getStockList(lst, stockURL):
html = getHTMLText(stockURL, "GB2312")
soup = BeautifulSoup(html, 'html.parser')
a = soup.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]d{6}", href)[0])
except:
continue
def getStockInfo(lst, stockURL, fpath):
count = 0
for stock in lst:
url = stockURL + stock + ".html"
html = getHTMLText(url)
try:
if html=="":
continue
infoDict = {}
soup = BeautifulSoup(html, 'html.parser')
stockInfo = soup.find('div',attrs={'class':'stock-bets'})
name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
infoDict.update({'股票名称': name.text.split()[0]})
keyList = stockInfo.find_all('dt')
valueList = stockInfo.find_all('dd')
for i in range(len(keyList)):
key = keyList[i].text
val = valueList[i].text
infoDict[key] = val
with open(fpath, 'a', encoding='utf-8') as f:
f.write( str(infoDict) + 'n' )
count = count + 1
print("r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
except:
count = count + 1
print("r当前进度: {:.2f}%".format(count*100/len(lst)),end="")
continue
def main():
stock_list_url = 'https://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'D:/BaiduStockInfo.txt'
slist=[]
getStockList(slist, stock_list_url)
getStockInfo(slist, stock_info_url, output_file)
main()
Scrapy爬虫框架
Scrapy爬虫框架介绍
Scrapy的安装
pip install scrapy
安装测试:scrapy -h
Scraoppy爬虫框架结构
爬虫框架:爬虫框架是实现爬虫功能的一个软件结构和功能组件集合
爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫
Scrapy爬虫框架解析
Engine(不需要修改)
控制所有模块之间的数据流
根据条件触发事件
Downloader:根据请求下载网页(不需要修改)
Scheduler:对所有爬取请求进行调度管理(不需要修改)
Downloader Middleware
目的:实施Engine、Scheduler和Downloader之间进行用户可配置的控制
功能:修改、丢弃、新增请求或响应
用户可以编写配置代码
Spider(需要用户编写配置代码)
解析Downloader返回的响应(Response)
产生爬取项(scraped item)
产生额外的爬取请求(Request)
Item Pipelines(需要用户编写配置文件)
以流水线方式处理Spider产生的爬取项
由一组操作顺序组成,类似流水线,每一个操作是一个Item Pipeline类型
可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库
Spider Middleware(用户可以编写配置代码)
目的:对请求和爬取项的再处理
功能:修改、丢弃、新增请求或爬取项
requests库和Scrapy爬虫的比较
相同点
两者都可以进行页面请求和爬取,python爬虫的两个重要技术路线
两者可用性都好,文档丰富,入门简单
两者都没有处理js、提交表单、应对验证码等功能(可扩展)
不同点
requests
页面级爬虫
功能库
并发性考虑不足,性能较差
重点在于页面下载
定制灵活
上手十分简单
Scrapy
网站级爬虫
框架
并发性好,性能较高
重点在于爬虫结构
一般定制灵活,深度定制困难
入门较难
选用哪个技术路线开发爬虫
非常小的需求,requests库
不太小的需求,Scrapy框架
定制程度很高的需求(不考虑规模),自搭框架,requests>Scrapy
Scrapy爬虫的常用命令
Scrapy命令行
Scrapy是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行
Scrapy命令行格式
>scrapy[options][args]
Scrapy常用命令
startproject:创建一个新工程
scrapy startproject
genspider:创建一个爬虫
scrapy genspider [options]
settings:获得爬虫配置信息
scrapy settings [options]
crawl:运行一个爬虫
scrapy crawl
list:列出工程中所有爬虫
scrapy list
shell:启动URL调试命令行
scrapy shell [url]
Scrapy爬虫的命令行逻辑
命令行更容易自动化,适合脚本控制
本质上,Scrapy是给程序员用的,功能更重要
Scrapy爬虫的基本使用
Scrapy爬虫的第一个实例
步骤1:建立一个Scrapy爬虫工程
python123deme:外层目录
scrapy.cfg:部署scrapy爬虫的配置文件
python123deme:scrapy框架的用户自定义python代码
__init__.py #初始化脚本 item.py #item代码模板(继承类) middlewares.py #Middlewares代码模板(继承类) pipelines.py #pipelines代码模板(继承类) settings.py #scrapy爬虫的配置文件 spiders/ #spiders代码模板目录(继承类)
步骤2:在工程中产生一个Scrapy爬虫
scrapy genspider demo python123.io #会在spiders目录下生成一个demo.py #demo.py # -*- coding: utf-8 -*- import scrapy class DemoSpider(scrapy.Spider): name = "demo" #allowed_domains = ["python123.io"] start_urls = ['https://python123.io/'] def parse(self, response): #用于处理响应,解析内容形成字典,发现新的URL爬取请求 pass
步骤3:配置产生的spider爬虫
#修改后的demo.py
# -*- coding: utf-8 -*-
import scrapy
class DemoSpider(scrapy.Spider):
name = "demo"
#allowed_domains = ["python123.io"]
start_urls = ['https://python123.io/ws/demo.html']
def parse(self, response):
fname = response.url.split('/')[-1]
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Saved file %s.' % name)
步骤4:运行爬虫,获取网页
scrapy crawl demo
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 #普通写法 def square(n): ls = [i**2 for i in range(n)] return ls for i in square(5): print(i,"",end="")
生成器相比一次列出所有内容的优势
更节省存储空间
响应更迅速
使用更灵活
生成器写法
import scrapy
class DemoSpider(scrapy.Spider):
name = "demo"
#allowed_domains = ["python123.io"]
def start_requests(self):
urls = [
'https://python123.io/ws/demo.html'
]
for url in urls:
yield scrapy.Request(url=url,callback=self.pares)
def parse(self, response):
fname = response.url.split('/')[-1]
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Saved file %s.' % name)
Scrapy爬虫的基本使用
Scrapy爬虫的使用步骤
步骤1:创建一个工程和spider模板
步骤2:编写spider
步骤3:编写item pipelines
步骤4:优化配置策略
Scrapy爬虫的数据类型
Request类:向网络上提交请求的内容
class scrapy.http.Request()
Request对象标识一个HTTP请求
由spider生成,由downloader执行
.url #Request对应的请求URL地址 .method #对应的请求方法,'GET'等 .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类:spider产生的信息
class scrapy.item.Item()
Item对象表示一个从HTML页面中提取的信息内容
由spider生成,由Item Pipeline处理
Item类似字典类型,可以按照字典类型操作
Scrapy爬虫提取信息的方法
Scrapy爬虫支持多种HTML信息提取方法
Beautiful Soup,lxml,re,XPath Selector,CSS Selector
CSS Selector的基本使用
.css('a::attr(href)').extract() #a-标签名称、href-标签属性
实例4:股票数据Scrapy爬虫
「股票数据Scrapy爬虫」实例介绍
功能描述
技术路线:scrapy
目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
「股票数据Scrapy爬虫」实例编写
步骤1:创建一个工程和spider模板
> scrapy startproject BaiduStocks
> cd BaiduStocks
> scrapy genspider stocks baidu.com
进一步修改spiders/stocks.py文件
步骤2:编写spider
配置stocks.py文件
修改对返回页面的处理
修改对新增URL爬取请求的处理
# -*- coding: utf-8 -*-
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = "stocks"
start_urls = ['https://quote.eastmoney.com/stocklist.html']
def parse(self, response):
for href in response.css('a::attr(href)').extract():
try:
stock = re.findall(r"[s][hz]d{6}", href)[0]
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
yield scrapy.Request(url, callback=self.parse_stock)
except:
continue
def parse_stock(self, response):
infoDict = {}
stockInfo = response.css('.stock-bets')
name = stockInfo.css('.bets-name').extract()[0]
keyList = stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
for i in range(len(keyList)):
key = re.findall(r'>.*', keyList[i])[0][1:-5]
try:
val = re.findall(r'd+.?.*', valueList[i])[0][0:-5]
except:
val = '--'
infoDict[key]=val
infoDict.update(
{'股票名称': re.findall('s.*(',name)[0].split()[0] +
re.findall('>.*<', name)[0][1:-1]})
yield infoDict
步骤3:编写item pipelines
配置pipelines.py文件
定义对爬取项(scraped Item)的处理类
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
class BaidustocksPipeline(object):
def process_item(self, item, spider):
return item
class BaidustocksInfoPipeline(object):
def open_spider(self, spider):
self.f = open('BaiduStockInfo.txt', 'w')
def close_spider(self, spider):
self.f.close()
def process_item(self, item, spider):
try:
line = str(dict(item)) + 'n'
self.f.write(line)
except:
pass
return item
配置ITEM_PIPELINES选项
下面是settings.py文件中被修改的区域:
# Configure item pipelines
# See https://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'BaiduStocks.pipelines.BaidustocksInfoPipeline': 300,
}



