赞
踩
这是北京理工大学MOOCpython爬虫基础课程的部分笔记,原视频在哔哩哔哩
网站地址:www.python-requests.org
安装
cmd中输入 pip install requests
或者cmd输入easy_install requests
或者下载安装包后放到library/python/3.7/site-packages
解决timeout报错,使用pip --default-timeout=100,修改时间
#IDLE中调试request库
import requests
r = requests.get("http://baidu.com")
#查看状态码,为200,表示访问成功
r.status_code
#更改网页编码
r.encoding = 'utf-8'
#打印网页内容
r.text
request库的7个主要方法,其他6个方法都是通过调用request方法实现的
requests.request() | 构造一个请求,支撑以下各个方法的基础 |
---|---|
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
ruquests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTML页面提交删除请求,对应于HTTP的DELETE |
request.get()方法
获取一个网页最简单的方法:
r = requests.get(url)
requests.get(url,params=None,**kwargs)
Response对象属性
r.status_code | HTTP请求的返回状态,200表示连接成功,404表示失败(除了200都是失败) |
---|---|
r.text | HTTP响应内容的字符串形式,即url对应的页面内容 |
r.encoding | 从HTTP header中猜测的响应内容编码方式 |
r.apparent_encoding | 从内容中分析出的相应内容编码方式(备选编码方式) |
r.content | HTTP响应内容的二进制形式 |
一般来说要先看r.status_code是不是200,是200才能调用r的其他属性
r.ending是从http header中的charset字段中获得的,如果有这个字段,说明网站对其编码形式已经做出了规定。但如果没有这个字段,将默认设为ISO-8859-1,这个编码不能解析中文。r.apparent_encoding从内容而不是头部得到编码,因此apparent_encoding更加准确,可以把apparent_encoding赋予encoding
异常 | 说明 |
---|---|
requests.ConnectionError | 网络联结错误异常,如DNS查询失败、拒绝联结等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 联结远程服务器超时异常 |
request.Timeout | 请求URL超时,产生超时异常 |
r.raise_for_status()方法可以判断r.status_code,如果不是200,就抛出requests.HTTPError异常
import requests
def getHTMLText(url):
try:
r = request.get(url,timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return t.text
except:
return "产生异常"
if __name__ == "__main__":
url = "http://baidu.com"
print(getHTMLText(url))
这个框架使得爬取网页更有效
http,Hypertext Transfer Protocol,超文本传输协议。
它是 一个基于“响应与请求”模式的无状态的应用层协议,简单说就是用户发出一些请求,服务器作出一些响应,无状态指的是第一次请求和第二次请求之间没有关联,应用层指的是该协议工作在php协议之上,协议一般采用url作为定位网络资源的标识。
url格式: http://host[:port][path]
host:合法的Internet主机域名或者IP地址
port:端口号,可以省略,缺省端口为80
path:资源在服务器上的内部路径
举例:
http://www.bit.edu.cn
http://220.181.111.188/duty [duty目录下的资源]
实际上url就是资源在网络上的存取路径,每一个url就是一个数据资源
HTTP协议对资源的操作:
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的响应信息报告,即获得该资源的头部信息 |
POST | 请求向URL位置的资源后附加新的数据 |
PUT | 请求向URL位置存储一个资源,覆盖原URL位置的资源 |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除 URL位置存储的资源 |
从互联网获得信息使用GET和HEAD方法,HEAD只获得一个梗概
向互联网传输信息使用PUT POST和PATCH方法
删除现有资源使用DELETE
每一次操作都是独立无状态的
假设URL位置有一组数据Userinfo,包括UserID、UserName等20个字段
需求:用户修改了Username,其他不便
应用:使用PATCH方法,重新提交Username的新的信息
使用PUT方法,需要提交所有的20个字段的信息
因此,PATCH方法可以节省网络带宽
#head方法 r = requests.head("http://httpbin.org/get") r.headers r.text #post方法 向URL POST一个字典自动编码为form(表单) payload = {'key1':'value1','key2':'value2'} r = requests.post('http://httpbin.org/post',data = payload) print(r.text) ## {··· "form":{ "key1":"value1", "key2":"value2" }, } #向这个URL提交data,将会被默认被存储到form字段下,如果提交字符串会被提交到data的字段下面
method:请求方式,对应get/put/post等7种方法
有GET HEAD POST PUT PATCH delete OPTIONS
OPTIONS和获取资源不直接相关,获取的是交互参数
url
**kwargs:13种控制访问参数
params:字典或者字节序列,作为参数增加到url中
#把一些键值对增加到了url中
kv = {'key1':'value1','key2':'value2'}
r = requests.request('GET','http://python123.io/ws',params=kv)
print(r.url)
##https://python123.io/ws?key1=value1&key2=value2
data:字典、字节序列或者文件对象,作为Request对象的内容,存入了url链接所对应的位置
body = "zhu ti nei rong"
r = requests.request('GET','http://python123.io/ws',data=body)
json:JSON格式的数据,作为Request的内容
headers:字典,HTTP定制头
hd = {'user-agent':'chrome/10'}
r = requests.ruquest('POST','http://python123.io/ws',headers=hd)
#修改url中的user-agent字段,模拟chrome/10浏览器访问
cookies:字典或者CookieJar,Request中的cookie
auth:元祖,支持HTTP认证功能
files字段:字典类型,向服务器传输文件时使用的字断
fp = {'file':open('shuju.xls','rb')}
r = requests.request('POST','http://python123.io/ws',file=fp)
timeout,设定的超时时间·,以秒为单位
proxies:字典类型,设定访问代理服务器,可以增加登陆认证
pxs = {'http':'http://user:pass@10.10.10.1:1234',
'https':'https://10.10.10.1:4321'}
r = requests.request('GET','http://baidu.com',proxies=pxxs)
#使用代理服务器的IP地址,避免被反扒
实际上7个方法中,除了get和head,其他的都被网站限制使用了
Robots Exclusion Standard 网络爬虫排除标准,作用是网站告知网络爬虫哪些页面可以抓取,哪些不行,在网站根目录下有个robots.txt文件
京东的robots协议:www.jd.com/robots.txt
User-agent: * #对于任何的user-agent都应该遵守如下协议 Disallow: /?* #不允许访问以?开头的数据 Disallow: /pop/*.html #不允许访问pop/*.html Disallow: /pinpai/*.html?* #符合pinpai/*.html?*通配符的不准爬取 #以下四个爬虫禁止访问任何资源 User-agent: EtaoSpider Disallow: / User-agent: HuihuiSpider Disallow: / User-agent: GwdangSpider Disallow: / User-agent: WochachaSpider Disallow: /
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
对任意的网络爬虫,应该首先识别robots.txt
robots协议是建议性的,不是必然要遵守的
类人行为可以不参考
import requests
url = "https://item.jd.com/100008348542.html"
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失败")
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<!-- shouji -->
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<title>【AppleiPhone 11】Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待【行情 报价 价格 评测】-京东</title>
<meta name="keywords" content="AppleiPhone 11,AppleiPhone 11,AppleiPhone 11报价,AppleiPhone 11报价"/>
<meta name="description" content="【AppleiPhone 11】京东JD.COM提供AppleiPhone 11正品行货,并包括AppleiPhone 11网购指南,以及AppleiPhone 11图片、iPhone 11参数、iPhone 11评论、iPhone 11心得、iPhone 11技巧等信息,网购AppleiPhone 11上京东,放心又轻松" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="mobile-agent" content="format=xhtml; url=//item.m.jd.com/product/100008348542.html">
<meta http-equiv="mobile-agent" content="format=html5; url=//item.m.jd.com/product/100008348542.html">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<link rel="canonical" href="//item.jd.com/100008348542.html"/>
<link rel="dns-prefetch" href="//misc.360buyimg.com"/
import requests
url = "https://www.amazon.cn/dp/B01MTSA6FU?ref_=Oct_RecCard_dsk_asin2&pf_rd_r=1R7PBZW24SN6QMKMW4W4&pf_rd_p=d7526bc5-3640-48d5-8d6b-448fefacc51e&pf_rd_m=A1AJ19PSB66TGU&pf_rd_s=desktop-4"
try:
kv = {'uesr-agent': 'Mozilla/5.0'}
#修改headers
r = requests.get(url, headers=kv)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失败")
'''
百度的关键词接口:http://www.baidu.com/s?wd=keyword
360的关键词接口: http://www.so.com/?sq=keyword
'''
kv = {'wd':'python'}
r = requests.get("http://www.baidu.com/s",params=kv) #使用params给url
print(r.status_code)
print(r.request.url)
print(len(r.text))
import requests import os url = "https://pic3.zhimg.com/80/v2-fd60996adc5dce7f78578271c6558278_qhd.jpg" 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('文件已经保存') else: print('文件已存在') except: print('爬取失败')
import requests
url = "http://m.ip138.com/ip.asp?ip"
##一个简单的方法查看接口,就是输入点什么东西,然后看看浏览器url的变化
try:
r = requests.get(url + '202.204.80.112')
r.raise_for_status()
r.encoding = r.apparent_encoding()
print(r.text[-500:])
except:
print('爬取失败')
官方地址:http://www.crummy.com/software/BeautifulSoup/
安装方法
cmd 中 pip install beautifulsoup4
在pycharm中导入已经安装的第三方库的办法:就是在interpreter里面安装,跟下载新的第三方库是一样的,pycharm为每个project指定的库是不一样的
或者新建一个project,新建时勾选inherit global site-packages,则会继承所有的第三方库
安装小测:
http://python123.io/ws/demo.html
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
#注意是这样的导入方式
from bs4 import BeautifulSoup
# 使用beautifulsoup对demo内容解析,使用html.parser解析器
soup = BeautifulSoup(demo,"html.parser")
print(soup.prettify())
#只用两行代码解析XML/HTML信息
form bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data</p>','html.parser')
beautifulsoup库的元素
只要提供的文件时标签类型,bs库都能解析
标签的理解
可以from bs4 import BeautiSoup,也可以直接import bs4
BeautifulSoup是一个类,HTML是一个文档,也是一个标签树,也可以转换为bs类,这就让标签树变成了一个变量
bs可以使用的解析器
解析器 | 使用方法 | 条件 |
---|---|---|
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 |
基本元素 | 说明 |
---|---|
Tag | 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾 |
Name | 标签的名字, … 的名字是’p’,格式:.name |
Attributes | 标签的属性,字典形式组织,格式:.attrs |
NavigableString | 标签内非属性字符串,<>…</>中字符串,格式:.string |
Comment | 标签内字符串的注视部分,一种特殊的Comment类型 |
import requests r = requests.get("https://python123.io/ws/demo.html") demo = r.text from bs4 import BeautifulSoup # 使用beautifulsoup对demo内容解析,使用html.parser解析器 soup = BeautifulSoup(demo,"html.parser") print(soup.title) #获取HTML页面中a标签,也就是a标签的内容 #如果html中存在多个标签,soup.tag只返回第一个标签 print(soup.a) tag = soup.a #获取a标签的名字 print(soup.a.name) #获取父标签的名字 print(soup.a.parent.name) #在获取p标签的父标签的名字 print(soup.a.parent.parent.name) #获取a标签的属性 print(tag.attrs) #属性是以字典的形式组织的,因此可以继续用字典的方式提取 #tag就是一个标签类型,叫做bs4.element.Tag #获取a标签的string信息 print(tag.string) #string类型被定义为bs4.element.NavigableString
Comment类型有点特殊
from bs4 import BeautifulSoup
newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a conment</p>","html.parser")
print(newsoup.b.string,type(newsoup.b.string))
print(newsoup.p.string,type(newsoup.p.string))
This is a comment <class 'bs4.element.Comment'>
This is not a conment <class 'bs4.element.NavigableString'>
看b标签里面是一个注释形式即 ,在打印的时候使用tag.string来提取,和navigablestring是一个打印方法,要确定是否是注释需要查看type类型
鉴于多次使用python123.io网站的html信息,直接打印一下吧
<html><head><title>This is a python demo page</title></head>
<body>
<p class="title"><b>The demo python introduces several python courses.</b></p>
<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>
</body></html>
这个树形结构总结和遍历方式:
标签树的下行遍历
属性 | 说明 |
---|---|
.contents | 子节点的列表,将所有儿子节点存入列表 |
.children | 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点 |
.decendants | 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历 |
标签树的上行遍历
属性 | 说明 |
---|---|
.parent | 节点的父亲标签 |
.parents | 节点先辈标签的迭代类型,用于循环遍历先辈节点 |
##试一试.contents打印出了什么
import requests
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,'html.parser')
s_head = soup.head
s_head_con = soup.head.contents
s_body = soup.body
s_body_con = soup.body.contents
#.contents获取了一个列表,可以遍历
print(soup.html.parent)
#最高级标签的parent是它自己
soup = BeautifulSoup(demo,"html.parser")
for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(paren.name)
属性 | 说明 |
---|---|
.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 |
.previous_sibling | 返回按照HTML文本顺序的上一个平行节点标签 |
.next_siblings | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 |
.previous_siblings | 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签 |
平行遍历的条件:平行遍历发生在同一个父节点下的各节点之间,不是一个父节点就不是平行遍历,平行遍历获取的不一定是标签类型,因为标签树之间的navigablestring也构成了标签树的节点,所以也有可能遍历到navigablestring类型
使用for循环遍历.next_siblings或者.previous_siblings
HTML的信息标记将超文本信息嵌入到文本之中
如果标签中没有内容,使用缩写形式
YAML中用缩进表示所属关系
JSON实例
YAML实例
思路:首先搜索到所有的<a>标签,然后解析<a>标签格式,提取herf后的链接内容
for link in soup.find_all('a'):
print(link.get('herf'))
<>.find_all(name,attrs,recrusive,string,**kwargs)
name:对标签名称的检索字符串
ss = soup.find_all(['a','b']) #同时查找a标签和b标签
#如果给出的标签是Ture,将显示文档中的所有标签名称
#找到以b开头的所有的信息
import re
for tag in soup.find_all(re.compile('b')):
print(tag.name)
attrs:对标签属性值的字符串,可以标准属性检索
查找P标签中包含”course"字符串的信息
ss = soup.find_all('p','course')
查找属性ip='link’的字段
ss = soup.find_all(id = 'link')
查找id属性中以link开头的字段
import re
ss = soup.find_all(id=re.compile('link'))
recursive,是否对子孙全部检索,默认为True,也就是对某一标签开始的所有子孙节点的信息,如果只是搜索某一节点儿子节点的信息,可以将recursive设置为False
ss = soup.find_all('a',recursive = False)
##[]儿子节点上没有a标签
ss = soup.find_all(string='Basic Pathon)
#需要精确地使用字符串
#检索含有python的字段
import re
ss = soup.find_all(string=re.compile(python))
(…)等价于.find_all()
soup(…)等价于soup.find_all()
方法 | 说明 |
---|---|
<>.find() | 搜索且只返回一个结果,字符串类型,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_parent() | 在先辈节点中值返回一个结果,字符串类型,同.find_all()参数 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型,同.find_all()参数 |
<>._next_sibling() | 在后续平行节点中返回一个结果,字符串类型,同.find_all()参数 |
<>.find_previous_siblings() | 在前续平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_previous_sibling() | 在前续平行节点中返回一个结果,字符串类型,同.find_all()参数 |
要求:
输入:大学排名的URL链接
输出:大学排名信息的屏幕输出(排名、大学名称、总分)
步骤:
1,从网络上获取大学排名网页内容
使用getHEMLText()
2,提取网页内容中信息到合适的数据结构
使用fillUnivList(),使用二维列表的形式
3,利用数据结构展示并输出内容
printUnivList(),输出结果
import bs4 import requests from bs4 import BeautifulSoup 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") # 找到tbody的所有信息,也就是找到所有大学的集合 for tr in soup.find('tbody').contents: #检测tr标签的类型,如果不是Tag则过滤[需要引用bs4库] #原来使用的是.children()方法,发生 'list_iterator' object is not callable'的类型错误,被迫使用.contents属性 if isinstance(tr,bs4.element.Tag): tds = tr('td') ulist.append([tds[0].string,tds[1].string,tds[2].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])) #num表示要打印多少个元素 def main(): ulist = [] url = "http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html" html = getHTMLText(url) fillUnivList(ulist,html) printUnivList(ulist,20) main()
/>>>
排名 学校名称 总分 1 清华大学 94.6 2 北京大学 76.5 3 浙江大学 72.9 4 上海交通大学 72.1 5 复旦大学 65.6 6 中国科学技术大学 60.9 7 华中科技大学 58.9 7 南京大学 58.9 9 中山大学 58.2 10 哈尔滨工业大学 56.7 11 北京航空航天大学 56.3 12 武汉大学 56.2 13 同济大学 55.7 14 西安交通大学 55.0 15 四川大学 54.4 16 北京理工大学 54.0 17 东南大学 53.6 18 南开大学 52.8 19 天津大学 52.3 20 华南理工大学 52.0
如何实现中文的输出对齐/格式化?
我也不太会←_←
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。