【第1周】网络爬虫之规则

单元1:Requests库入门

Requests库安装

命令提示符,pip安装

Requests库的7个主要方法

方法 说明
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库的get()方法

r=requests.get(url)

构造一个向服务器请求资源的Requests对象,返回一个包含服务器资源的Response对象。
完整方法为

requests.get(url, params = None, **kwargs)
  • url:获取页面的url链接
  • params:url中的额外参数,字典或字节流格式,可选
  • **kwargs:12个控制访问的参数

调用.requests()方法实现

2个重要对象:Response和Requests
Response对象包含爬虫返回的内容

Response对象的属性

属性 说明
r.status_code HTTP请求的返回状态,200表示连接成功,404表示失败
r.text HTTP响应内容的字符串形式,即,url对应的页面内容
r.encoding 从HTTP header中猜测的响应内容编码方式
r.apparent_encoding 从内容中分析出的响应内容编码方式(备用编码方式)
r.content HTTP响应内容的二进制形式

爬取网页的通用代码框架

网络连接有危险,异常处理很重要。
理解Requests的异常

异常 说明
requests.ConnectionError 网络连接错误异常,如DNS查询失败、拒绝连接等
requests.HTTPError HTTP错误异常
requests.URLRequired HRL缺失异常
requests.TooManyRedirects 超过最大重定向次数,产生重定向异常
requests.ConnectTimeout 连接远程服务器超时异常
requests.Timeout 请求URL超时,产生超时异常

理解Requests库的异常

异常 说明
r.raise_for_status() 如果不是200,产生异常requests.HTTPError

爬取网页的通用代码框架

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 = "http://www.baidu.com"
    print(getHTMLText(url))

HTTP协议及Requests库方法

Requests有7个主要方法
理解HTTP协议:

  • 超文本传输协议
  • 基于请求与响应模式的、无状态的应用层协议
  • 采用URL作为定位网络资源的标识http://host[:port][path],host:合法的Internet主机域名或地址;port:端口号,默认80;path:请求资源的路径
  • URL:通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源

HTTP协议对资源的操作

方法 说明
GET 请求获取URL位置的资源
HEAD 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息
POST 请求向URL位置的资源后附加新的数据
PUT 请求向URL位置存储一个资源,覆盖原URL位置的资源
PATCH 请求局部更新URL位置的资源,即改变该处资源的部分内容
DELETE 请求删除URL位置存储的资源
HTTP协议对资源的操作

每一次操作独立无状态。

理解PATCH和PUT区别:
假设URL位置有一组数据UserInfo,包括UserID、UserName等20个字段。
需求:用户只修改了UserName。

  • 采用PATCH,仅向URL提交UserName的局部更新请求
  • 采用PUT,必须将所有20个字段一并提交到URL,未提交字段被删除

与Requests库方法一一对应

head()方法

  • 用很少流量获取网络资源概要信息

post()方法

  • 向URL POST一个字典,自动编码为form(表单)
  • POST一个字符串,自动编码为data

put()方法:

  • 与post()方法类似,将原数据覆盖掉

Requests库主要方法解析

7个主要方法

requests.request(method, url, **kwargs)
  • method:请求方式,对应get/put/post等7种
  • **kwargs:控制访问的参数,13种:
    params:字典或字节序列,作为参数增加到url中
    data:字典、字节序列或文件对象,作为Request的内容
    json:JSON格式的数据,作为Requests的内容
    headers:字典,HTTP定制头
    cookies:字典或CookieJar,Request中的cookie
    auth:元组,支持HTTP认证功能
    files:字典类型,传输文件
    timeout:设定超时时间,秒为单位
    proxies:字典类型,设定访问代理服务器,可以增加登录认证
    allow_redirects:True/False,默认为True,重定向开关
    stream:True/False,默认为True,获取内容立即下载开关
    verify:True/False,默认为True,认证SSL证书开关
    cert:本地SSL证书路径
requests.get(url, params = None, **kwargs)
  • params:url中的额外参数,字典或字节流格式,可选
  • **kwargs:12个控制访问的参数
requests.head(url, **kwargs)
  • **kwargs:13个控制访问参数
requests.post(url, data = None, json = None, **kwargs)
  • data:字典、字节序列或文件,Request的内容
  • json:JSON格式的数据,Request的内容
  • **kwargs:11个控制访问参数
requests.put(url, data = None, **kwargs)
  • data:字典、字节序列或文件,Request的内容
  • **kwargs:12个控制访问参数
requests.patch(url, data = None, **kwargs)
  • data:字典、字节序列或文件,Request的内容
  • **kwargs:12个控制访问参数
requests.delete(url, **kwargs)
  • **kwargs:13个控制访问参数

由于网络安全限制,最常用的是get()方法

单元2:网络爬虫的“盗亦有道”

网络爬虫引发的问题

网络爬虫尺寸:

  • 爬取网页,玩转网页:小规模,数据量小,爬取速度不敏感,Requests库
  • 爬取网站,爬取系列网站:中规模,数据规模较大,爬取速度敏感,Scrapy库
  • 爬取全网:大规模,搜索引擎,爬取速度关键,定制开发

网络爬虫的“骚扰”

受限于编写水平和目的,网络爬虫会对Web服务器带来巨大的资源开销。

网络爬虫的法律风险

服务器上的数据有产权归属。
网络爬虫获取数据后牟利将带来法律风险。

网络爬虫泄露隐私

网络爬虫可能具备突破简单访问控制的能力,获得被保护数据从而泄露个人隐私。

限制网络爬虫

来源审查:判断User-Agent进行限制

  • 只响应浏览器或友好爬虫的访问

发布公告:Robots协议

  • 告知所有爬虫网站的爬取策略,需要爬虫遵守

Robots协议

Robots Exclusion Standard 网络爬虫排除标准
作用:告知网络爬虫哪些页面可以抓取,哪些不行。
形式:在网站根目录下的robots.txt文件
例如:京东的Robots协议:https://www.jd.com/robots.txt

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: /

Robots协议基本语法

# 注释,*代表所有,/代表根目录
User-agent: *
Disallow: /

Robots协议的遵守方式

Robots协议的使用

网络爬虫:自动或人工识别robots.txt文件,再进行内容爬取。
约束性:Robots协议是建议但非约束性,如果不遵守可能存在法律风险。
类人行为可以不参考Robots协议。

单元3:Requests网络爬虫实战

实例1:京东商品页面的爬取

爬取商品:https://item.jd.com/100002716279.html

>>> import requests
>>> r = requests.get("https://item.jd.com/100002716279.html")
>>> r.status_code
200
>>> r.encoding
'gbk'
>>> r.text[:1000]
'<!DOCTYPE HTML>\n<html lang="zh-CN">\n<head>\n    <!-- shouji -->\n    <meta http-equiv="Content-Type" content="text/html; charset=gbk" />\n    <title>【AppleiPad mini】Apple iPad mini 5 2019年新款平板电脑 7.9英寸(64G WLAN版/A12芯片/MUQW2CH/A)深空灰色【行情 报价 价格 评测】-京东</title>\n    <meta name="keywords" content="AppleiPad mini,AppleiPad mini,AppleiPad mini报价,AppleiPad mini报价"/>\n    <meta name="description" content="【AppleiPad mini】京东JD.COM提供AppleiPad mini正品行货,并包括AppleiPad mini网购指南,以及AppleiPad mini图片、iPad mini参数、iPad mini评论、iPad mini心得、iPad mini技巧等信息,网购AppleiPad mini上京东,放心又轻松" />\n    <meta name="format-detection" content="telephone=no">\n    <meta http-equiv="mobile-agent" content="format=xhtml; url=//item.m.jd.com/product/100002716279.html">\n    <meta http-equiv="mobile-agent" content="format=html5; url=//item.m.jd.com/product/100002716279.html">\n    <meta http-equiv="X-UA-Compatible" content="IE=Edge">\n    <link rel="canonical" href="//item.jd.com/100002716279.html"/>\n        <link rel="dns-prefetch" href="//mi'

说明页面返回信息,全部代码为:

import requests
url = "https://item.jd.com/100002716279.html"
try:
    r = requests.get(url)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[:1000])
except:
    print("爬取失败")

实例2:亚马逊商品页面的爬取

爬取商品:https://www.amazon.cn/dp/B005T63BEM/ref=lp_1559274071_1_1?s=electronics&ie=UTF8&qid=1569760137&sr=1-1

>>> import requests
>>> r = requests.get("https://www.amazon.cn/dp/B005T63BEM/ref=lp_1559274071_1_1?s=electronics&ie=UTF8&qid=1569760137&sr=1-1")
>>> r.status_code
200
>>> r.encoding
'UTF-8'
>>> r.text[:1000]
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n    \n\n    \n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n        \n            \n            \n        \n\n\n\n\n\n \n \n\n\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    \n\n\n\n\n\n    <!doctype html><html class="a-no-js" data-19ax5a9jf="dingo">\n    <head><script>var aPageStart = (new Date()).getTime();</script><meta charset="utf-8">\n\n    \n\n\n\n    <link rel="dns-prefetch" href="//images-cn.ssl-images-amazon.com">\n\n\n\n\n  \n\n\n\n\n    \n\n\n\n\n\n\n    \n    \n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    \n    \n\n\n    \n    \n\n\n\n\n\n\n\n\n\n\n\n\n<script type="text/javascript">\nvar iUrl = "https://images-cn.ssl-images-amazon.com/images/I/415tpDfFbTL._SX300_QL70_.jpg";\n(function(){var i=new Image; i.src = iUrl;})();\n</script>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n\n   \n    \n\n\n\n\n\n\n\n<!--  -->\n<link rel="stylesheet" href="https://images-cn.ssl-images-amazon.com/images/I/21kpNOwB5dL._RC|71IGFd-taTL.css,11WnO6PP7GL.css,31ltTjVHNDL.css,21SfF47-e2L.css,31lx9mSsVLL.css,11g4B3l0OAL.css,312fqnjyyJL.c'
>>> r.request.headers
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

User-Agent为'python-requests/2.22.0,如果被拒绝,可以更改头部信息的User-Agent为其他浏览器。

>>> kv = {'User-Agent':'Mozilla/5.0'}
>>> url = 'https://www.amazon.cn/dp/B005T63BEM/ref=lp_1559274071_1_1?s=electronics&ie=UTF8&qid=1569760137&sr=1-1'
>>> r = requests.get(url, headers = kv)
>>> r.status_code
200
>>> r.request.headers
{'User-Agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
>>> r.text[:1000]
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  \n  \n\n\n\n\n\n\n\n    \n\n    \n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n\n\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    \n\n\n\n\n\n    <!doctype html><html class="a-no-js" data-19ax5a9jf="dingo">\n    <head>\n<script type="text/javascript">var ue_t0=ue_t0||+new Date();</script>\n<script type="text/javascript">\nwindow.ue_ihb = (window.ue_ihb || window.ueinit || 0) + 1;\nif (window.ue_ihb === 1) {\nvar ue_hob=+new Date();\nvar ue_id=\'E5W4931DMCTPC168HBBY\',\nue_csm = window,\nue_err_chan = \'jserr-rw\',\nue = {};\n(function(d){var e=d.ue=d.ue||{},f=Date.now||function(){return+new Date};e.d=function(b){return f()-(b?0:d.ue_t0)};e.stub=function(b,a){if(!b[a]){var c=[];b[a]=function(){c.push([c.slice.call(arguments),e.d(),d.ue_id])};b[a].replay=function(b){for(var a;a=c.shift();)b(a[0],a[1],a[2])};b[a].isStub=1}};e.exec=function(b,a){return function(){try{return b.apply(this,arguments)}catch(c){ueLogError(c,{attribution:a||"undefined",logLevel:"WARN"})}}}})(ue_csm);\n\nue.stub(ue,"log");ue.stub(ue,"onunload");ue.stub(ue,"onflu'

全部代码

import requests
url = 'https://www.amazon.cn/dp/B005T63BEM/ref=lp_1559274071_1_1?s=electronics&ie=UTF8&qid=1569760137&sr=1-1'
try:
    kv = {'User-Agent':'Mozilla/5.0'}
    r = requsts.get(url, headers = kv)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.text[1000:2000])
except:
    print('爬取失败')

实例3:百度/360搜索关键词提交

自动提交关键词并获得结果。
搜索引起关键词提交接口
百度关键词接口:http://www.baidu.com/s?wd=keyword
360关键词接口:http://www.so.com/s?q=keyword
使用params

>>> import requests
>>> kv = {'wd':'Python'}
>>> r = requests.get('http://www.baidu.com/s', params = kv)
>>> r.status_code
200
>>> r.request.url
'http://www.baidu.com/s?wd=Python'
>>> len(r.text)
358258

完整代码

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('爬取失败')

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('爬取失败')

实例4:网路图片的爬取和存储

网络图片链接的格式:
http://www.example.com/picture.jpg
图片网址为:https://www.nationalgeographic.com/content/dam/expeditions/landing-pages/North-America/hero-national-parks2.adapt.1900.1.jpg
保存为C盘abc.jpg

>>> import requests
>>> path = 'C:/abc.jpg'
>>> url = 'https://www.nationalgeographic.com/content/dam/expeditions/landing-pages/North-America/hero-national-parks2.adapt.1900.1.jpg'
>>> r = requests.get(url)
>>> r.status_code
200
>>> with open(path, 'wb') as f:
    f.write(r.content)

    
300340
>>> f.close()

完整代码为

import requests
import os
url = 'https://www.nationalgeographic.com/content/dam/expeditions/landing-pages/North-America/hero-national-parks2.adapt.1900.1.jpg'
root = "C://"
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地址归属地的自动查询

通过ip138网站提交ip地址后,链接变为:
http://m.ip138.com/ip.asp?ip=ipaddress

>>> f.close()
>>> import requests
>>> url = 'http://m.ip138.com/ip.asp?ip='
>>> r = requests.get(url + '202.204.80.112')
>>> r.status_code
200
>>> r.text[-500:]
'value="查询" class="form-btn" />\r\n\t\t\t\t\t</form>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class="query-hd">ip138.com IP查询(搜索IP地址的地理位置)</div>\r\n\t\t\t\t<h1 class="query">您查询的IP:202.204.80.112</h1><p class="result">本站主数据:北京市海淀区 北京理工大学 教育网</p><p class="result">参考数据一:北京市 北京理工大学</p>\r\n\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<div class="footer">\r\n\t\t\t<a href="http://www.miitbeian.gov.cn/" rel="nofollow" target="_blank">沪ICP备10013467号-1</a>\r\n\t\t</div>\r\n\t</div>\r\n\r\n\t<script type="text/javascript" src="/script/common.js"></script></body>\r\n</html>\r\n'

完整代码

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('爬取失败')

许多网站人机交互都是以链接的方式提交,知道提交的链接形式可以用Python模拟提交。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容