北理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个控制访问的参数

1
2
3
4
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的类型。

1
type(r)
requests.models.Response

可以看到r是Response类型的,这里再来看下Response对象的属性

1
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'}
1
r.status_code
200

status_code是状态相应码,如果是200表示正常,否则为异常,所以后续处理的时候要使用try…except

1
r.encoding
'ISO-8859-1'

encoding从HTTP header中猜测的响应内容编码方式。如果header中不存在charset,则认为编码为ISO‐8859‐1。
r.text根据r.encoding显示网页内容。这也就是为什么之前的内容中有乱码,因为内容里有中文,而编码方式为’ISO-8859-1’。

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超时,产生超时异常

结合上述异常处理以及编码问题,这里老师给了一个爬取网页的通用代码框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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&amp;tpl=mn&amp;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>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
1
2
3
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次的时间。下面尝试下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

1
2
3
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:京东商品页面的爬取

1
2
3
4
5
6
7
8
9
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:亚马逊商品页面的爬取

1
2
3
import requests
r=requests.get("https://www.amazon.cn/gp/product/B01M8L5Z3Y")
r.status_code
200

这部分结果和老师的就有所不同了,老师那边返回的是503,查看结果之后发现是代理user-agent了问题,所以对user-agent进行了设置,这里两种均尝试下

1
2
3
4
5
6
7
8
9
10
#未修改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 .
1
2
3
4
5
6
7
8
9
10
11
#修改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

1
2
3
4
5
6
7
8
9
10
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的关键词接口:

http://www.so.com/s?q=keyword

1
2
3
4
5
6
7
8
9
10
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
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>