python3爬虫——urlllib使用
Posted ->大胖子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python3爬虫——urlllib使用相关的知识,希望对你有一定的参考价值。
参考内容:1.https://www.cnblogs.com/Lands-ljk/p/5447127.html 2.https://cuiqingcai.com/947.html
1.分分钟扒一个网页下来
怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它是一段HTML代码,加 JS、CSS,如果把网页比作一个人,那么HTML便是他的骨架,JS便是他的肌肉,CSS便是它的衣服。所以最重要的部分是存在于HTML中的,下面我们就写个例子来扒一个网页下来。
from urllib.request import urlopen response=urlopen("http://www.baidu.com") html=response.read().decode(\'utf-8\') print(html)
是的你没看错,真正的程序就两行,把它保存成 demo.py,进入该文件的目录,执行如下命令查看运行结果,感受一下。
2.分析扒网页的方法
那么我们来分析这两行代码,第一行
response=urlopen("http://www.baidu.com")
首先我们调用的是urllib库里面的request下的urlopen方法,传入一个URL,这个网址是百度首页,协议是HTTP协议,当然你也可以把HTTP换做FTP,FILE,HTTPS 等等,只是代表了一种访问控制协议,urlopen一般接受三个参数。使用方法如下:
urllib.request.
urlopen
(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
- url: 需要打开的网址
- data:Post提交的数据
- timeout:设置网站的访问超时时间
第一个参数URL是必须要传送的,在这个例子里面我们传送了百度的URL,执行urlopen方法之后,返回一个response对象,返回信息便保存在这里面。
如果不加read:直接打印出了该对象的描述。所以记得一定要加read方法,否则它不出来内容可就不怪我咯!
直接用urllib.request模块的urlopen()获取页面,page的数据格式为bytes类型,需要decode()解码,转换成str类型。
1 from urllib import request 2 response = request.urlopen(r\'http://python.org/\') # <http.client.HTTPResponse object at 0x00000000048BC908> HTTPResponse类型 3 page = response.read() 4 page = page.decode(\'utf-8\')
urlopen返回对象提供方法:
- read() , readline() ,readlines() , fileno() , close() :对HTTPResponse类型数据进行操作
- info():返回HTTPMessage对象,表示远程服务器返回的头信息
- getcode():返回Http状态码。如果是http请求,200请求成功完成;404网址未找到
- geturl():返回请求的url
3.构造Request
其实上面的urlopen参数可以传入一个request请求,它其实就是一个Request类的实例,构造时需要传入Url,Data等等的内容。比如上面的两行代码,我们可以这么改写
from urllib import request req=request.Request("http://www.baidu.com") print(req) response=request.urlopen(req) html=response.read() html = html.decode(\'utf-8\') print(html)
运行结果是完全一样的,只不过中间多了一个request对象,推荐大家这么写,因为在构建请求时还需要加入好多内容,通过构建一个request,服务器响应请求得到应答,这样显得逻辑上清晰明确。
urllib.request.
Request
(url, data=None, headers={}, method=None)
使用request()来包装请求,再通过urlopen()获取页面。
再比如:(这里加入参数headers)
有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性。
首先,打开我们的浏览器,调试浏览器F12,我用的是Edge浏览器,打开网络监听,示意如下,比如知乎,点登录之后,我们会发现登陆之后界面都变化了,出现一个新的界面,实质上这个页面包含了许许多多的内容,这些内容也不是一次性就加载完成的,实质上是执行了好多次请求,一般是首先请求HTML文件,然后加载JS,CSS 等等,经过多次请求之后,网页的骨架和肌肉全了,整个网页的效果也就出来了。
其中,\'User-Agent\'就是请求的身份,如果没有写入请求身份,那么服务器不一定会响应,所以可以在headers中设置agent,例如下面的例子,这个例子只是说明了怎样设置的headers,小伙伴们看一下设置格式就好。
url = r\'http://www.lagou.com/zhaopin/Python/?labelWords=label\' headers = { \'User-Agent\': r\'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \' r\'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3\', \'Referer\': r\'http://www.lagou.com/zhaopin/Python/?labelWords=label\', \'Connection\': \'keep-alive\' } req = request.Request(url, headers=headers) page = request.urlopen(req).read() page = page.decode(\'utf-8\')
用来包装头部的数据:
- User-Agent :这个头部可以携带如下几条信息:浏览器名和版本号、操作系统名和版本号、默认语言
- Referer:可以用来防止盗链,有一些网站图片显示来源http://***.com,就是检查Referer来鉴定的
- Connection:表示连接状态,记录Session的状态。
这样,我们设置了一个headers,在构建request时传入,在请求时,就加入了headers传送,服务器若识别了是浏览器发来的请求,就会得到响应。
另外,我们还有对付”反盗链”的方式,对付防盗链,服务器会识别headers中的referer是不是它自己,如果不是,有的服务器不会响应,所以我们还可以在headers中加入referer,如上程序。这里refer就是你要访问的地址。
4.POST和GET数据传送
上面的程序演示了最基本的网页抓取,不过,现在大多数网站都是动态网页,需要你动态地传递参数给它,它做出对应的响应。所以,在访问时,我们需要传递数据给它。最常见的情况是什么?对了,就是登录注册的时候呀。
把数据用户名和密码传送到一个URL,然后你得到服务器处理之后的响应,这个该怎么办?下面让我来为小伙伴们揭晓吧!
数据传送分为POST和GET两种方式,两种方式有什么区别呢?
最重要的区别是GET方式是直接以链接形式访问,链接中包含了所有的参数,当然如果包含了密码的话是一种不安全的选择,不过你可以直观地看到自己提交了什么内容。POST则不会在网址上显示所有的参数,不过如果你想直接查看提交了什么就不太方便了,大家可以酌情选择。
(1)POST
urllib.request.
urlopen
(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
urlopen()的data参数默认为None,当data参数不为空的时候,urlopen()提交方式为Post。
一个例子:
from urllib import request, parse url = r\'http://www.lagou.com/jobs/positionAjax.json?\' headers = { \'User-Agent\': r\'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \' r\'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3\', \'Referer\': r\'http://www.lagou.com/zhaopin/Python/?labelWords=label\', \'Connection\': \'keep-alive\' } data = { \'first\': \'true\', \'pn\': 1, \'kd\': \'Python\' } data = parse.urlencode(data).encode(\'utf-8\') req = request.Request(url,data=data, headers=headers, ) page = request.urlopen(req).read() page = page.decode(\'utf-8\') print(page)
urllib.parse.urlencode
(query, doseq=False, safe=\'\', encoding=None, errors=None)
urlencode()主要作用就是将url附上要提交的数据。
data = { \'first\': \'true\', \'pn\': 1, \'kd\': \'Python\' } data = parse.urlencode(data).encode(\'utf-8\')
经过urlencode()转换后的data数据为?first=true?pn=1?kd=Python,最后提交的url为
http://www.lagou.com/jobs/positionAjax.json?first=true?pn=1?kd=Python
Post的数据必须是bytes或者iterable of bytes,不能是str,因此需要进行encode()编码
当然,也可以把data的数据封装在urlopen()参数中。
另一个例子:
现在我们要模拟登陆CSDN:当然下面代码可能登陆不进去,因为CSDN还有个流水号的字段,没有设置全,比较复杂在这里就不写上去了,在此只是说明登录的原理。一般的登录网站一般是这种写法。
values={\'username\':"xxxxx@qq.com","password":"xxxx"} data=parse.urlencode(values).encode(\'utf-8\')
我们需要定义一个字典,名字为values,参数我设置了username和password,下面利用urllib的urlencode方法将字典编码,命名为data,构建request时传入两个参数,url和data,运行程序,返回的便是POST后呈现的页面内容。
(2)GET
至于GET方式我们可以直接把参数写到网址上面,直接构建一个带参数的URL出来即可。
values={\'username\':"xxxxx@qq.com","password":"xxxx"} data=parse.urlencode(values).encode(\'utf-8\') url="http://passport.csdn.net/account/login" geturl=url+"?"+data req = request.Request(geturl ) page = request.urlopen(req).read() page = page.decode(\'utf-8\') print(page)
你可以print geturl,打印输出一下url,发现其实就是原来的url加?然后加编码后的参数
和我们平常GET访问方式一模一样,这样就实现了数据的GET方式传送。
5、其他一些高级功能
1. Proxy(代理)的设置
urllib.request.
ProxyHandler
(proxies=None)
当需要抓取的网站设置了访问限制,这时就需要用到代理来抓取数据。
data = { \'first\': \'true\', \'pn\': 1, \'kd\': \'Python\' } proxy = request.ProxyHandler({\'http\': \'5.22.195.215:80\'}) # 设置proxy opener = request.build_opener(proxy) # 挂载opener request.install_opener(opener) # 安装opener data = parse.urlencode(data).encode(\'utf-8\') page = opener.open(url, data).read() page = page.decode(\'utf-8\') return page
urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。假如一个网站它会检测某一段时间某个IP 的访问次数,如果访问次数过多,它会禁止你的访问。所以你可以设置一些代理服务器来帮助你做工作,每隔一段时间换一个代理,网站君都不知道是谁在捣鬼了,这酸爽!(下面程序是复制的python2的写法)
2.Timeout 设置
上一节已经说过urlopen方法了,第三个参数就是timeout的设置,可以设置等待多久超时,为了解决一些网站实在响应过慢而造成的影响。
例如下面的代码,如果第二个参数data为空那么要特别指定是timeout是多少,写明形参,如果data已经传入,则不必声明。
6、异常处理
1.URL ERROR
首先解释下URLError可能产生的原因:
- 网络无连接,即本机无法上网
- 连接不到特定的服务器
- 服务器不存在
在代码中,我们需要用try-except语句来包围并捕获相应的异常。下面是一个例子
from urllib import request, parse
url = r\'http://www.lagou.com/jobs/positionAjax.json?\'
headers = {
\'User-Agent\': r\'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \'
r\'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3\',
\'Referer\': r\'http://www.lagou.com/zhaopin/Python/?labelWords=label\',
\'Connection\': \'keep-alive\'
}
data = {
\'first\': \'true\',
\'pn\': 1,
\'kd\': \'Python\'
}
data = parse.urlencode(data).encode(\'utf-8\')
req = request.Request(url, headers=headers)
try:
page = request.urlopen(req, data=data).read()
page = page.decode(\'utf-8\')
except request.URLError as e:
print(e.code())
print(e.read().decode(\'utf-8\'))
2.HTTP ERROR
HTTPError是URLError的子类,在你利用urlopen方法发出一个请求时,服务器上都会对应一个应答对象response,其中它包含一个数字”状态码”。举个例子,假如response是一个”重定向”,需定位到别的地址获取文档,urllib2将对此进行处理。其他不能处理的,urlopen会产生一个HTTPError,对应相应的状态吗,HTTP状态码表示HTTP协议所返回的响应的状态。
比如:
from urllib import request, parse url = r\'http://www.lagou.com/jobs/positionAjax.json?\' headers = { \'User-Agent\': r\'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \' r\'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3\', \'Referer\': r\'http://www.lagou.com/zhaopin/Python/?labelWords=label\', \'Connection\': \'keep-alive\' } data = { \'first\': \'true\', \'pn\': 1, \'kd\': \'Python\' } data = parse.urlencode(data).encode(\'utf-8\') req = request.Request(url, headers=headers) try: page = request.urlopen(req, data=data).read() page = page.decode(\'utf-8\') except request.HTTPError as e: print(e.code())
print(e.read().decode(\'utf-8\')) except request.URLError as e: print(e.reason().decode(\'utf-8\')) else: print("OK")
以上是关于python3爬虫——urlllib使用的主要内容,如果未能解决你的问题,请参考以下文章