第054讲: 论一只爬虫的自我修养2:实战 | 学习记录(小甲鱼零基础入门学习Python)

(标答出处: 鱼C论坛)
《零基础入门学习Python》


本节知识点:


今天我们在实战中来进行学习,会举两个例子:
第一个例子是我们会下载一只猫,
第二个例子是我们用Python来模拟浏览器通过在线的有道翻译进行文本的翻译。

(一)使用Python下载一只猫

我们常说,林子大了,什么鸟都有。互联网这么大,那当然不管什么样的奇葩网站都会有。我们今天举的例子就是要访问一个 http://placekitten.com/, 这个网站是为猫农量身定制的一个站点,网站后面你只需要加上 /宽度/高度,就可以得到一只相应宽度和高度的猫的图片。这些图片都是JPG格式的,你可以通过右键将其简单保存到桌面上。

我们第一个例子就是使用Python实现刚才的操作,事实上我们上节课教过的内容也是完全足够的,我们新建一个 download_cat.py 文件。

首先,我们需要 import urllib.request,然后使用urlopen() 函数得到 response,得到的 cat_img 可以用一个文件保存,我们命名这个文件为 cat_500_600.jpg,我们说过,图片也是文件,它也是二进制数据组成的,我们这里用 ‘wb’ 将收到的二进制数据写入 jpg 格式的文件就可以了。

import urllib.request

url = 'http://www.placekitten.com/g/500/600'
response = urllib.request.urlopen(url).read()
with open ('cat_img.jpg','wb') as f :
    f.write(response)

运行之后,就在桌面上有了一张 名为 cat_500_600.jpg 的图片。我们接着继续解释一下上面的代码:

上节课,我们说过,urlopen() 函数中的 url 参数可以是字符串,也可以是 Request object,其实,在上面的程序中,我们传入的是地址字符串,它也是将地址字符串转换为 Request 对象,然后再将对象传入 urlopen() 函数。因此,

response = urllib.request.urlopen("http://placekitten.com/500/600")
#等价于
req = urllib.request.Resquest("http://placekitten.com/500/600")
response = urllib.request.urlopen(req)

另外,urlopen() 函数返回的 response 其实是一个对象(object),看下图文档解释,因此你可以使用 read() 方法来读取内容,
在这里插入图片描述
文档还告诉我们,除了可以使用 read() 方法之外,还可以是使用 geturl() 、info() 和 getcode() 方法,我们试一下这三个函数分别返回什么:

我们运行 download_cat.py 之后,调用这几个方法:

>>> 
=========== RESTART: C:\Users\XiangyangDai\Desktop\download_cat.py ===========
>>> response.geturl()
'http://placekitten.com/500/600'
>>> response.info()
<http.client.HTTPMessage object at 0x00000150F729AB70>
>>> print(response.info())
Date: Tue, 11 Dec 2018 06:57:33 GMT
Content-Type: image/jpeg
Content-Length: 20921
Connection: close
Set-Cookie: __cfduid=d2f9e8e46b6e9940463cf24baf0b7f0fb1544511453; expires=Wed, 11-Dec-19 06:57:33 GMT; path=/; domain=.placekitten.com; HttpOnly
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=86400
Expires: Wed, 12 Dec 2018 06:57:33 GMT
CF-Cache-Status: HIT
Accept-Ranges: bytes
Vary: Accept-Encoding
Server: cloudflare
CF-RAY: 48760ec5d6fc99c1-LAX
 
>>> response.getcode()
200

geturl() 得到的就是你访问的具体的地址;

info() 得到的是一个 HTTPMessage 的对象,你可以将它打印出来,包含了 远程服务器返回的 Head 信息;

getcode() 返回的是 Http 的状态码,200 表示 OK,就是正常响应。

(二)利用在线有道翻译来翻译文本
在这里插入图片描述
我们要看的是 Network 这一块,当我们点下自动翻译按钮时,在下面会看到有很多 Method,其中有 Get , 有Post ,这些内容都是浏览器与客户端的通信内容,在客服端与服务器之间进行请求的时候,两种最常用的方法:一种就是Get,一种就是 Post,在定义上来说,Get是指从服务器请求获得数据,而Post是向指定服务器提交被处理的数据,当然在现实情况中,Get也常常用作提交数据。但是我们这里有 Post,刚刚我们是提交数据,提交 I love you!这个语句让它翻译,我们点进去:
在这里插入图片描述
在这里插入图片描述
equest URL:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule,有人会认为 urlopen()函数打开的应该是 http://fanyi.youdao.com/ 这个地址,其实在内部嵌入的是前面的这个地址,你要实现翻译的机制是在这。

Request Method:POST,请求的方法是 Post 的形式。

Status Code:200 OK,状态码 200 表示正常响应。如果是 404 就是页面不见了。更多关于HTTP状态码的信息请查阅:

HTTP状态码大全

Remote Address 是服务器的 IP 地址加上打开的端口号。

Resquest Headers:是客服端(这里就是浏览器,用 Python代码的时候就是我们的代码)发送请求的Headers,这个常常用于服务端来判断是否非人类访问,什么意思呢?假设我们写一个 Python 代码,然后用这个代码批量的访问网站的数据,这样子,服务器的压力就很大了,所以呢,服务器一般是不欢迎非人类的访问的。一般我们就是使用Resquest Headers里面的User-Agent来识别是浏览器访问还是代码访问,大家可以看到,这里的User-Agent显示的系统的架构是(Windows NT 10.0; WOW64),后面你还包括浏览器的核心及其版本号等信息。如果你使用Python 访问的话,这个User-Agent默认就是 Python URL 3.5,这样就可能被屏蔽掉。(不过呢,如果服务器君以为这样就可以阻挡我们前进的脚步的话,他就太天真了,这个User-Agent是可以进行自定义的,嘻嘻,后面会给大家介绍)
在这里插入图片描述
上面蓝色文字已经写得很清楚了(这些内容来自urllib的Python文档的urllib.request部分),urlopen有一个data参数,如果这个参数被赋值,那么它就是以POST的形式取代GET的形式,也就是说,如果data = None的话,就默认是以GET的形式。这里还说了,data参数必须是基于application/x-www-form-urlencoded的格式,它还很贴心的告诉我们,你可以使用urllib.parse.urlencode()函数将字符串转换为所需要的形式。

事实上,我们有了这两段话的描述,我们就可以来写代码了:(命名为:translation.py

import urllib.request
import urllib.parse
import json

comment = input('请输入要翻译的句子:')
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
data = {}
data['i'] = comment
data['from'] = 'AUTO'
data['to'] = 'AUTO'
data['smartresult'] = 'dict'
data['client'] = 'fanyideskweb'
data['salt'] = '15525619941724'
data['sign'] = '503edca828b35b367b2166bc10a30193'
data['ts'] = '1552561994172'
data['bv'] = 'f355c521b6e13c15aa35c72a097b7786'
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['action'] = 'FY_BY_REALTlME'
data['typoResult'] = 'false'
data = urllib.parse.urlencode(data).encode('utf-8')

response = urllib.request.urlopen(url,data)
html = response.read().decode('utf-8')
target = json.loads(html)
print ('翻译结果为:',target['translateResult'][0][0]['tgt'])

测试题


在这里插入图片描述
答:timeout 参数用于设置连接的超时时间,单位是秒。
在这里插入图片描述
答:

response = urllib.request.urlopen(url)
code = response.getcode()

在这里插入图片描述
答:GET 和 POST。
在这里插入图片描述
答:发出请求的永远是客户端,做出响应的永远是服务端。
在这里插入图片描述
答:普通浏览器会通过该内容向访问网站提供你所使用的浏览器类型、操作系统、浏览器内核等信息的标识。
在这里插入图片描述
答:urlopen 函数有一个 data 参数,如果给这个参数赋值,那么 HTTP 的请求就是使用 POST 方式;如果 data 的值是 None,也就是默认值,那么 HTTP 的请求就是使用 GET 方式。
在这里插入图片描述
答:decode。decode 的作用是将其他编码的字符串转换成 unicode 编码,相反,encode 的作用是将 unicode 编码转换成其他编码的字符串。
在这里插入图片描述
答:JSON 是一种轻量级的数据交换格式,说白了这里就是用字符串把 Python 的数据结构封装起来,便与存储和使用。


动动手


在这里插入图片描述

import easygui as g
import urllib.request as ur

def main() :
    msg='请填写需要的喵的照片的尺寸'
    title = '下载一只喵'
    use_into = g.multenterbox(msg,title,('宽','高'))

    while 1:
        if use_into == None:
            break
        errmsg = ""
 
        try:
            width = int(use_into[0].strip())
        except:
            errmsg += "宽度必须为整数!"
 
        try:
            height = int(use_into[1].strip())
        except:
            errmsg += "高度必须为整数!"    
 
        if errmsg == "":
            break
        
        use_into = g.multenterbox(errmsg, title, ('宽','高'))
    
    url = 'http://www.placekitten.com/g/'
    responces = ur.urlopen(url+use_into[0]+'/'+use_into[1]).read()
    filepath = g.diropenbox("请选择存放喵的文件夹")
 
    if filepath:
        filename = '%s/cat_%d_%d.jpg' % (filepath, width, height)
    else:
        filename = 'cat_%d_%d.jpg' % (width, height)
 
    with open(filename, 'wb') as f:
        f.write(responces)
 
if __name__ == "__main__":
    main()

在这里插入图片描述
Python2 实现的代码:

# -- coding:gbk --
import re
import urllib, urllib2, cookielib
 
loginurl = 'https://www.douban.com/accounts/login'
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
 
params = {
"form_email":"your email",
"form_password":"your password",
"source":"index_nav" #没有的话登录不成功
}
 
#从首页提交登录
response=opener.open(loginurl, urllib.urlencode(params))
 
#验证成功跳转至登录页
if response.geturl() == "https://www.douban.com/accounts/login":
    html=response.read()
 
    #验证码图片地址
    imgurl=re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)
    if imgurl:
        url=imgurl.group(1)
        #将图片保存至同目录下
        res=urllib.urlretrieve(url, 'v.jpg')
        #获取captcha-id参数
        captcha=re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)
        if captcha:
            vcode=raw_input('请输入图片上的验证码:')
            params["captcha-solution"] = vcode
            params["captcha-id"] = captcha.group(1)
            params["user_login"] = "登录"
            #提交验证码验证
            response=opener.open(loginurl, urllib.urlencode(params))
            ''' 登录成功跳转至首页 '''
            if response.geturl() == "http://www.douban.com/":
                print 'login success ! '

答:Python 3 对比 Python 2 有不少的改变。

在本题中:

urllib 和 urllib2 合并,大多数功能放入了 urllib.request 模块;
原来的 urllib.urlencode() 变为 urllib.parse.urlencode().encode(),由于编码的关系,你还需要在后边加上 encode(‘utf-8’);
cookielib 被改名为 http.cookiejar;
课堂中我们还没讲,所以这里借机会给大家简单科普一下 cookie 是什么东西:

我们说 HTTP 协议是基于请求响应模式,就是客户端发一个请求,服务端回复一个响应酱紫……

但 HTTP 协议是无状态的,也就是说客户端这会儿给服务端提交了账号密码,服务端回复验证通过,但下一秒客户端说我要访问 XXOO 资源,服务端回复:“啊??你是谁?!”

为了解决这个尴尬的困境,有人就发明出了 cookie。cookie 相当于服务端(网站)用于验证你的身份的密文。于是客户端每次提交请求的时候,服务端通过验证 cookie 即可知道你的身份信息。那么正如你所猜测的,CookieJar 是 Python 用于存放 cookie 的对象。

当然,这里已经给你提供了 Python 2 的代码,你不懂上边这些,也不影响完成作业。

import re
import urllib.request
from http.cookiejar import CookieJar
 
# 豆瓣的登录url 
loginurl = 'https://www.douban.com/accounts/login'
cookie = CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor)
 
data = {
    "form_email":"your email",
    "form_password":"your password",
    "source":"index_nav"
}
data = {}
data['form_email'] = '你的账号'
data['form_password'] = '你的密码'
data['source'] = 'index_nav'
 
response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))
 
#验证成功跳转至登录页
if response.geturl() == "https://www.douban.com/accounts/login":
    html = response.read().decode()
    
    #验证码图片地址
    imgurl = re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)
    if imgurl:
        url = imgurl.group(1)
        # 将验证码图片保存至同目录下
        res = urllib.request.urlretrieve(url, 'v.jpg')
 
        # 获取captcha-id参数
        captcha = re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)
 
        if captcha:
            vcode = input('请输入图片上的验证码:')
            data["captcha-solution"] = vcode
            data["captcha-id"] = captcha.group(1)
            data["user_login"] = "登录"
 
            # 提交验证码验证
            response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))
 
            # 登录成功跳转至首页 '''
            if response.geturl() == "http://www.douban.com/":
                print('登录成功!')

猜你喜欢

转载自blog.csdn.net/qq_38970783/article/details/88541070
今日推荐