北理Python爬虫Week1
课程地址:https://www.icourse163.org/course/BIT-1001870001
笔记内容结合课件整理。
这里对北理爬虫课程第一周内容回顾,本周主要介绍了requests库的使用
1.Request库入门
首先来看下request的基本使用,基本使用如下
requests.get(url, params=None, **kwargs)
url : 拟获取页面的url链接
params : url中的额外参数,字典或字节流格式,可选
**kwargs: 12个控制访问的参数
import requests
r=requests.get("http://www.baidu.com")
print(r.status_code)
r.text[:400]
200
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>ç\x99¾åº¦ä¸\x80ä¸\x8bï¼\x8cä½\xa0å°±ç\x9f¥é\x81\x93</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=h'
这里可以看到r.text内容有乱码,这里是编码的问题,后续会处理。
再来看下r的类型。
type(r)
requests.models.Response
可以看到r是Response类型的,这里再来看下Response对象的属性
r.headers
{'Server': 'bfe/1.0.8.18', 'Date': 'Sun, 13 May 2018 02:09:06 GMT', 'Content-Type': 'text/html', 'Last-Modified': 'Mon, 23 Jan 2017 13:28:36 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'}
r.status_code
200
status_code是状态相应码,如果是200表示正常,否则为异常,所以后续处理的时候要使用try…except
r.encoding
'ISO-8859-1'
encoding从HTTP header中猜测的响应内容编码方式。如果header中不存在charset,则认为编码为ISO‐8859‐1。
r.text根据r.encoding显示网页内容。这也就是为什么之前的内容中有乱码,因为内容里有中文,而编码方式为’ISO-8859-1’。
r.apparent_encoding
'utf-8'
apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)。根据网页内容分析出的编码方式
可以看作是r.encoding的备选。所以一般处理的时候会让r.encoding=r.apparent_encoding
这里再来看下Request库具体的异常种类。
异常 | 说明 |
---|---|
requests.ConnectionError | 网络连接错误异常,如DNS查询失败、拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时,产生超时异常 |
结合上述异常处理以及编码问题,这里老师给了一个爬取网页的通用代码框架
import requests
def getHTMLText(url):
try:
r=requests.get(url,timeout=30)
r.raise_for_status()#如果状态码不是200,引发HTTPError异常
r.encoding=r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__=="__main__":
url="http://www.baidu.com"
print(getHTMLText(url))
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
if __name__=="__main__":
url="www.baidu.com"
print(getHTMLText(url))
产生异常
最后来看下Requests库的7个主要方法,其实一般也就get,head使用的比较多,更加具体的部分可以参考老师的课件。
方法 | 说明 |
---|---|
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库的爬取性能分析,找一个网页,计算其爬取100次的时间。下面尝试下
import requests
import time
def getHTMLText(url):
try:
r=requests.get(url,timeout=30)
r.raise_for_status()
r.encoding=r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__=="__main__":
url="https://www.baidu.com/"
start=time.time()
for i in range(100):
getHTMLText(url)
end=time.time()
print(end-start)
15.708888530731201
2.网络爬虫的“盗亦有道”
首先来看下网络爬虫引发的问题,主要有对服务器的性能骚扰,使用数据牟利的法律风险以及用户隐私泄露。
再来看下网页堆网络爬虫的限制,主要有两种:
- 来源审查:判断User‐Agent进行限制
检查来访HTTP协议头的User‐Agent域,只响应浏览器或友好爬虫的访问 - 发布公告:Robots协议
告知所有爬虫网站的爬取策略,要求爬虫遵守
Robots协议
Robots Exclusion Standard,网络爬虫排除标准
作用:
网站告知网络爬虫哪些页面可以抓取,哪些不行
形式:
在网站根目录下的robots.txt文件
Robots协议具体案例
Robots协议基本语法:
* 代表所有,/代表根目录
具体形式为
User‐agent: *
Disallow: /
后续来看几个具体案例
京东robots
if __name__=="__main__":
url="https://www.jd.com/robots.txt"
print(getHTMLText(url))
User-agent: *
Disallow: /?*
Disallow: /pop/*.html
Disallow: /pinpai/*.html?*
User-agent: EtaoSpider
Disallow: /
User-agent: HuihuiSpider
Disallow: /
User-agent: GwdangSpider
Disallow: /
User-agent: WochachaSpider
Disallow: /
来分析下这段内容的含义:
User-agent: *
Disallow: /?*
Disallow: /pop/*.html
Disallow: /pinpai/*.html?*
这一段的意思对于任何爬虫,均不能访问后缀为/?*,/pop/*.html,/pinpai/*.html?* 的网页
User-agent: EtaoSpider
Disallow: /
User-agent: HuihuiSpider
Disallow: /
User-agent: GwdangSpider
Disallow: /
User-agent: WochachaSpider
Disallow: /
这几段的意思是EtaoSpider,HuihuiSpider,GwdangSpider,WochachaSpider这几个网络爬虫不能访问京东的任何页面。
3.Request库网络爬取实战
这一部分来看几个具体案例
实例1:京东商品页面的爬取
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])
except:
print("爬取失败")
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<!-- shouji -->
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<title>【华为荣耀8】荣耀8 4GB+64GB 全网通4G手机 魅海蓝【行情 报价 价格 评测】-京东</title>
<meta name="keywords" content="HUAWEI荣耀8,华为荣耀8,华为荣耀8报价,HUAWEI荣耀8报价"/>
<meta name="description" content="【华为荣耀8】京东JD.COM提供华为荣耀8正品行货,并包括HUAWEI荣耀8网购指南,以及华为荣耀8图片、荣耀8参数、荣耀8评论、荣耀8心得、荣耀8技巧等信息,网购华为荣耀8上京东,放心又轻松" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="mobile-agent" content="format=xhtml; url=//item.m.jd.com/product/2967929.html">
<meta http-equiv="mobile-agent" content="format=html5; url=//item.m.jd.com/product/2967929.html">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<link rel="canonical" href="//item.jd.com/2967929.html"/>
<link rel="dns-prefetch" href="//misc.360buyimg.com"/>
<link rel="dns-prefetch" href="//static.360buyimg.com"/>
<link rel="dns-prefetch" href="//img10.360buyimg.com"/>
<link rel="dns
实例2:亚马逊商品页面的爬取
import requests
r=requests.get("https://www.amazon.cn/gp/product/B01M8L5Z3Y")
r.status_code
200
这部分结果和老师的就有所不同了,老师那边返回的是503,查看结果之后发现是代理user-agent了问题,所以对user-agent进行了设置,这里两种均尝试下
#未修改user-agent
import requests
url="https://www.amazon.cn/gp/product/B01M8L5Z3Y"
try:
r=requests.get(url)
r.raise_for_status()
r.encoding=r.apparent_encoding
print(r.text[2000:3000])
except:
print("爬取失败")
ges-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_top_left._V1_.png)}.ap_popover_unsprited .ap_header .ap_right{background-image:url(https://images-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_top_right._V1_.png)}.ap_popover_unsprited .ap_header .ap_middle{background-image:url(https://images-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_top._V1_.png)}.ap_popover_unsprited .ap_footer .ap_left{background-image:url(https://images-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_bottom_left._V1_.png)}.ap_popover_unsprited .ap_footer .ap_right{background-image:url(https://images-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_bottom_right._V1_.png)}.ap_popover_unsprited .ap_footer .ap_middle{background-image:url(https://images-cn.ssl-images-amazon.com/images/G/28/javascripts/lib/popover/images/po_bottom._V1_.png)}.ap_popover_sprited .ap_body .ap_left,.ap_popover_sprited .
#修改user-agent
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_encoding
print(r.text[2000:3000])
except:
print("爬取失败")
om.amazon.csm.nexusclient.prod',
ue_navtiming=1,
ue_fcsn=1,
ue_isrw=true,
ue_fpf='//fls-cn.amazon.cn/1/batch/1/OP/AAHKV2X7AFYLW:462-6324598-2062068:EE3CSP6EGPZB02RRZ8RQ$uedata=s:',
ue_qsl=2000,
ue_rpl_ns=0,
ue_orct=1,
ue_int=0,
ue_adb=1,
ue_adb_rtla=1,
ue_ddq=1,
ue_sspb=0,
ue_rsc=0,
ue_clf=0,
ue_cdt=0,
ue_pel=0,
ue_wdg_imp=0;
if (!window.ue_csm) {var ue_csm = window;}
function ue_viz(){(function(c,e,a){function k(b){if(c.ue.viz.length<p&&!l){var a=b.type;b=b.originalEvent;/^focus./.test(a)&&b&&(b.toElement||b.fromElement||b.relatedTarget)||(a=e[m]||("blur"==a||"focusout"==a?"hidden":"visible"),c.ue.viz.push(a+":"+(+new Date-c.ue.t0)),"visible"==a&&(ue.isl&&uex("at"),l=1))}}for(var l=0,f,g,m,n=["","webkit","o","ms","moz"],d=0,p=20,h=0;h<n.length&&!d;h++)if(a=n[h],f=(a?a+"H":"h")+"idden",d="boolean"==typeof e[f])g=a+"visibilitychange",m=(a?a+"V":"v")+"isibilityState";
k({});d&&e.addEventListener(g,k,0);c.ue&&d&&(c.ue.pageViz={event:g,propHid:f})})(ue_csm,document,window)};
(function(a,
这部分和之前结果竟然不一样,也是挺神奇的,后续再探索原因。
实例3:百度/360搜索关键字提交
百度的关键词接口:
http://www.baidu.com/s?wd=keyword
import requests
keyword="Python"
try:
kv={'wd':keyword}
r=requests.get("http://www.baidu.com/s",params=kv)
print(r.request.url)
r.raise_for_status()
print(len(r.text))
except:
print("爬取失败")
http://www.baidu.com/s?wd=Python
273450
360的关键词接口:
import requests
keyword="Python"
try:
kv={'q':keyword}
r=requests.get("http://www.so.com/s",params=kv)
print(r.request.url)
r.raise_for_status()
print(len(r.text))
except:
print("爬取失败")
https://www.so.com/s?q=Python
296504
实例4:网络图片的爬取和存储
网络图片链接的格式:
http://www.example.com/picture.jpg
国家地理:http://www.nationalgeographic.com.cn/
选择一个图片Web页面:
http://www.nationalgeographic.com.cn/photography/photo_of_the_day/3921.html
右键复制图片地址
http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg
import requests
import os
url="http://image.nationalgeographic.com.cn/2017/0211/20170211061910157.jpg"
root=r"E:/北理爬虫课程/"
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("爬取失败")
文件保存成功
实例5:IP地址归属地的自动查询
这里老师提供了一个可以查询ip归属地的网站:
http://m.ip138.com/ip.asp?ip=ipaddress
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("爬取失败")
value="查询" class="form-btn" />
</form>
</div>
<div class="query-hd">ip138.com IP查询(搜索IP地址的地理位置)</div>
<h1 class="query">您查询的IP:202.204.80.112</h1><p class="result">本站主数据:北京市海淀区 北京理工大学 教育网</p><p class="result">参考数据一:北京市 北京理工大学</p>
</div>
</div>
<div class="footer">
<a href="http://www.miitbeian.gov.cn/" rel="nofollow" target="_blank">沪ICP备10013467号-1</a>
</div>
</div>
<script type="text/javascript" src="/script/common.js"></script></body>
</html>