看了原视频网站的教学视频,感觉内容讲解深入浅出,为加深个人理解,总结如下。
0.学习思路
Requests库:自动爬取HTML页面,自动网络请求提交。
Robots.text: 网络爬虫排除标准。
Beautiful Soup: 解析HTML页面。
project1: 2019年中国最好大学排名爬取
1.Requests库
安装方式同一般Python库的安装:Windows系统打开cmd,输入pip install requests
。
1.1 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()函数为基础,故用该函数也能将后六种函数表述出来。网络爬虫主要使用requests.get()函数。
1.2 requests库的一些常用函数:
.status_code 查看状态
import requests
r = requests.get("url")
r.status_code #输出运行状态码,若为200,则说明get成功,否则get失败
.encoding 通过访问Heading信息确定编码方式。
r.encoding 输出:'utf-8'
.apparent_encoding 从内容中分析出的响应内容编码方式(备选编码方式)。
apparent_encoding为备选编码方案,当encoding无法返回编码方式,可用该方法进行查询。故该方法更为准确。当r.status_code返回错误,或encoding编码生成结果出现乱码时,采用r.encoding=r.apparent_encoding再输出即可。
r.apparent_encoding 输出:‘utf-8’
.headers 输出头部信息
r.headers
输出:{'Server': 'bfe/1.0.8.18', 'Date': 'Thu, 28 Feb 2019 06:25:24 GMT', 'Content-Type': 'text/html', 'Last-Modified': 'Mon, 23 Jan 2017 13:28:24 GMT', 'Transfer-Encoding': 'chunked', 'Connection': 'Keep-Alive', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Pragma': 'no-cache', 'Set-Cookie': 'BDORZ=27315; max-age=86400; domain=.baidu.com; path=/', 'Content-Encoding': 'gzip'}
.content HTTP响应内容的二进制形式(二进制图片)
1.3 模拟浏览器发布请求方法
requests库使用的基本程序
import requests
r = requests.get(url)
r.status_code #查询返回状态
r.encoding = r.apparent_encoding
r.text
但是,有些网站具备识别功能,识别出为计算机访问时便阻止访问。我们可以查看一下自己的请求。
r.request.headers
输出:{'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
可以发现,这里的User-agent为python-requests/2.18.4,即识别为python访问而非浏览器,故为使得访问通过,需要进行代码的改进。
模拟浏览器访问
kv = {'user-agent':'Chrome'}
r=requests.get(url, headers = kv)
r.status_code
r.encoding = r.apparent_encoding
r.requests.headers
输出:{'user-agent': 'Chrome', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
即可通过。
爬取网页的通用代码框架
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout = 30)
r.raise_for_status() #如果状态不是200,引发error异常
except:
return "产生异常"
if _name_ == "_main_":
url = ""
print(getHTMLText(url))
2. HTTP协议与Robots协议
HTTP,Hypertext Transfer Protocol,超文本传输协议HTTP是一个基于“请求与响应”模式的、无状态的应用层协议(用户,服务器) URL格式:http://host[:port][path] host:合法的Internet主机域名或IP地址 port:端口号,缺省端口为80 path:请求资源的路径。
Robots Exclusion Standard 网络爬虫排除标准作用:网站告知网络爬虫哪些页面可以抓取,哪些不行。 形式:在网站根目录下的robots.txt文件
3. BeautifulSoup(美丽汤)
美丽汤解析模板:
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data</p>','html.parser')
BeautifulSoup的基本元素
- BeautifulSoup库是解析、遍历、维护“标签树”的功能库。
- p标签:
<p class="title">...</p> #<p>..</p>: 标签Tag Name/属性Attributes(0个或多个)
BeautifulSoup的基本元素:
名称 | 解释说明 |
---|---|
Tag | 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾。 |
Name | 标签的名字,格式:<标签> .name |
attributes | 标签的属性,字典形式组织,格式:<标签>.attrs |
NavigableString | 标签内非属性字符串,<>…</>中字符串,格式<标签>.string |
Comment | 标签内字符串的注释部分,一种特殊的Comment类型 |
3.1 基本元素程序示例
3.1.1 标签(Tag)
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
soup.title
输出:<title>
权力的游戏 第一季 (豆瓣)
</title>
获取标签内容
tag = soup.a #获取标签内容(只能获取一个)
tag
输出:<a class="nav-login" href="https://accounts.douban.com/passport/login?source=movie" rel="nofollow">登录/注册</a>
通过获取标签名,进行上下的遍历:
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
soup.a.name
输出:‘a’
soup.a.parent.name
输出:'div'
soup.a.parent.parent.name
输出:‘div’
3.1.2 属性
通过已知标签名,获得该标签下的所有属性
tag=soup.a
tag.attrs
输出:{'class': ['nav-login'],
'href': 'https://accounts.douban.com/passport/login?source=movie',
'rel': ['nofollow']}
通过已知标签名的属性名,获得属性内容
tag.attrs['href']
输出:'https://accounts.douban.com/passport/login?source=movie'
tag.attrs['class']
输出:['nav-login']
3.1.3 字符串
通过美丽汤的标签,获得该标签下的字符串内容:
soup.a
输出:<a class="nav-login" href="https://accounts.douban.com/passport/login?source=movie" rel="nofollow">登录/注册</a>
soup.a.string
输出:'登录/注册'
3.1.4 Comment
from bs4 import BeautifulSoup
newsoup=BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>","html.parser")
newsoup.b.string
输出:'This is a comment'
type(newsoup.b.string)
输出:bs4.element.Comment
newsoup.p.string
输出:'This is not a comment'
type(newsoup.p.string)
输出:bs4.element.NavigableString
3.2 上行遍历,平行遍历,下行遍历
标签的遍历查询
for parent in soup.a.parents:
if parent is None:
print(parent)
else:print(parent.name)
输出:div
div
div
body
html
[document]
平行遍历:平行遍历发生在同一个父亲节点下的各个子节点
soup.a.next_sibling
soup.a.previous_sibling
4. 信息标记
标记后的信息可形成信息组织结构,增加了信息的维度;标记后的信息可用于通信、存储或展示;标记的结构与信息一样具有重要价值;标记后的信息更利于程序理解和运用。
4.1 信息标记的三种形式
HTML的信息标记(hyper text markup language)
HTML是www(world wide web)的信息组织方式。
超文本(声音+图像+视频) + 文本
XML 扩展标记语言 Internet上的信息交互与传递,结构类似HTML。
结构类似:<img src = 'china.jpg' size = "10">...</img>
JSON 移动应用云端和节点的信息通信,无注释。
主要通过键值对表示。例如:“name”(键 key):"外国语中学"(值 value) (需要增加引号来表示字符串)
一个键对应多个值时:
“name”:["外国语中学",“私立中学”] #多值情况,需要使用[,]表示
键值对的嵌套使用:
“name”:{
"newname": "外国语中学",
“oldname”: "私立中学"
} #键值对嵌套使用
YAML 各类系统的配置文件,有注释易读。
键值对表示,无类型:name(键 key):外国语中学(值 value) #不需要双引号
缩进关系表达嵌套所属关系:
name :
newName : 外国语中学
oldName : 私立中学
YAML用-号表达并列关系:
name:
-外国语高中
-私立高中
|表示整块数据,#表示注释
key : value
key : #Comment
-value1
-value2
key :
subkey : subvalue
4.2 信息提取的一般方法
方法一:完整解析信息的标记形式,再提取关键信息。
XML JSON YAML 需要标记解析器,例如bs4库的标签树遍历
优点 :信息解析准确 缺点 :提取过程繁琐,速度慢。
方法二:无视标记形式,直接搜索关键信息。
优点:提取过程简单,速度较快。
缺点:提取结果准确性与信息内容有关。
采取方法——两种方法融合
例如:提取HTML中所有URL链节
思路:1)搜索到所有标签。
2)解析标签格式,提取href后的链节内容。
<>.find_all(name, attrs, recursive, string, **kwargs) #信息搜索方法
返回一个列表类型,村春查找结果。
name:对标签名称的检索字符串。
soup.find_all('a') #返回所有a标签内容
soup.find_all(true) #返回所有标签内容
import re
for tag in soup.find_all(re.compile('b')):
print(tag.name) #re为正则表达式,该代码返回包含b的所有标签名字
attrs:对标签属性值的检索字符串,可标注属性检索。
soup.find_all('p','course') #返回具有course属性值的所有p标签
soup.find_all(id = 'link1') #返回id属性中含有link1的标签元素
soup.find_all(id = 'link') #需要精确描述属性值,只描述部分信息则返回为空
通过引入正则表达式,可通过寻找含有部分信息的属性或标签,即解决上述第三个程序问题
import re
soup.find_all(id = re.compile('link')) #此时即可正常返回含有link1的标签元素
recursive:是否对子孙全部检索,默认True.
string:<>…</>中字符串区域的检索字符串。
soup.find_all(string = 'Basic python')
['Basic Python']
利用正则表达式,通过检索某些特定字符将含有该字符的所有string搜索打印。
import re
soup.find_all(string = re.compile("Python"))
['This is a python demo page','the demo python introduce several python courses.']
一些简写方法:
<tag>(...)等价于<tag>.find_all(...)
soup(...)等价于soup.find_all(...)
5. 中国大学排名定向爬虫
功能描述:
输入:大学排名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): #检验tr是否为标签格式,引入库bs4
tds = tr('td') #定义tr标签下td标签为tds
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 = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) #输出前20所
main()
输出结果的表格并不对齐,这里主要原因是因为中文字符与英文字符数长度不同导致,这里可以提前声明英文字符进行扩展。
首先介绍格式化输出字符含义:
字符 | 含义 |
---|---|
{} | 槽 |
^ | 表示居中,后面数字表示槽长度 |
: | 冒号前面应有数值(默认0,1,2),为format函数中参数 |
修改后程序为:
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)
修改完成后,运行成功,结果如下图所示。