Python——论一只爬虫的自我修养2:实战

测试题:
0. urlopen() 方法的 timeout 参数用于设置什么?
1. 如何从 urlopen() 返回的对象中获取 HTTP 状态码?
2. 在客户端和服务器之间进行请求-响应时,最常用的是哪两种方法?
3. HTTP 是基于请求-响应的模式,那是客户端发出请求,服务端做出响应;还是服务端发出请求,客户端做出响应呢?
4. User-Agent 属性通常是记录什么信息?
5. 如何通过 urlopen() 使用 POST 方法像服务端发出请求?
6. 使用字符串的什么方法将其它编码转换为 Unicode 编码?
7. JSON 是什么鬼?
动动手:
0. 配合 EasyGui,给“下载一只猫“的代码增加互动:
 

  • 让用户输入尺寸;
  • 如果用户不输入尺寸,那么按默认宽400,高600下载喵;
  • 让用户指定保存位置。


程序实现如下图:
Python——论一只爬虫的自我修养2:实战

Python——论一只爬虫的自我修养2:实战

Python——论一只爬虫的自我修养2:实战

1. 写一个登录豆瓣的客户端。
这道题可能要难为大家了,因为需要 N 多你没学过的知识!
不过我也不打算让你断送希望,下边是一个可行的 Python 2 的代码片段,请修改为 Python 3 版本。其中一些库和知识点你可能还没学过,但凭借着过人的自学能力,你可以在不看答案的情况下完成任务的,对吗?
程序实现如下图:

Python——论一只爬虫的自我修养2:实战

Python 2 实现代码:

  1. # -- coding:gbk --
  2. import re
  3. import urllib, urllib2, cookielib
  4.  
  5. loginurl = 'https://www.douban.com/accounts/login'
  6. cookie = cookielib.CookieJar()
  7. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
  8.  
  9. params = {
  10. "form_email":"your email",
  11. "form_password":"your password",
  12. "source":"index_nav" #没有的话登录不成功
  13. }
  14.  
  15. #从首页提交登录
  16. response=opener.open(loginurl, urllib.urlencode(params))
  17.  
  18. #验证成功跳转至登录页
  19. if response.geturl() == "https://www.douban.com/accounts/login":
  20.     html=response.read()
  21.  
  22.     #验证码图片地址
  23.     imgurl=re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)
  24.     if imgurl:
  25.         url=imgurl.group(1)
  26.         #将图片保存至同目录下
  27.         res=urllib.urlretrieve(url, 'v.jpg')
  28.         #获取captcha-id参数
  29.         captcha=re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)
  30.         if captcha:
  31.             vcode=raw_input('请输入图片上的验证码:')
  32.             params["captcha-solution"] = vcode
  33.             params["captcha-id"] = captcha.group(1)
  34.             params["user_login"] = "登录"
  35.             #提交验证码验证
  36.             response=opener.open(loginurl, urllib.urlencode(params))
  37.             ''' 登录成功跳转至首页 '''
  38.             if response.geturl() == "http://www.douban.com/":
  39.                 print 'login success ! '
  40.  

复制代码


图一时之快先看答案,您将失去一次锻炼的机会!
请先自己动手,再回复查看参考答案。
测试题答案:


0. urlopen() 方法的 timeout 参数用于设置什么?
答:timeout 参数用于设置连接的超时时间,单位是秒。
1. 如何从 urlopen() 返回的对象中获取 HTTP 状态码?
答:

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

复制代码


2. 在客户端和服务器之间进行请求-响应时,最常用的是哪两种方法?
答:GET 和 POST。
3. HTTP 是基于请求-响应的模式,那是客户端发出请求,服务端做出响应;还是服务端发出请求,客户端做出响应呢?
答:发出请求的永远是客户端,做出响应的永远是服务端。
4. User-Agent 属性通常是记录什么信息?
答:普通浏览器会通过该内容向访问网站提供你所使用的浏览器类型、操作系统、浏览器内核等信息的标识。
5. 如何通过 urlopen() 使用 POST 方法像服务端发出请求?
答:urlopen 函数有一个 data 参数,如果给这个参数赋值,那么 HTTP 的请求就是使用 POST 方式;如果 data 的值是 NULL,也就是默认值,那么 HTTP 的请求就是使用 GET 方式。
6. 使用字符串的什么方法将其它编码转换为 Unicode 编码?
答:decode。decode 的作用是将其他编码的字符串转换成 unicode 编码,相反,encode 的作用是将 unicode 编码转换成其他编码的字符串。
7. JSON是什么鬼?
答:JSON 是一种轻量级的数据交换格式,说白了这里就是用字符串把 Python 的数据结构封装起来,便与存储和使用。


动动手答案:


0. 配合 EasyGui,给“下载一只猫“的代码增加互动。
代码清单:

  1. import easygui as g
  2. import urllib.request
  3.  
  4. def main():
  5.     msg = "请填写喵的尺寸"
  6.     title = "下载一只喵"
  7.     fieldNames = ["宽:", "高:"]
  8.     fieldValues = []
  9.     size = width, height = 400, 600
  10.     fieldValues = g.multenterbox(msg, title, fieldNames, size)
  11.  
  12.     while 1:
  13.         if fieldValues == None:
  14.             break
  15.         errmsg = ""
  16.  
  17.         try:
  18.             width = int(fieldValues[0].strip())
  19.         except:
  20.             errmsg += "宽度必须为整数!"
  21.  
  22.         try:
  23.             height = int(fieldValues[1].strip())
  24.         except:
  25.             errmsg += "高度必须为整数!"    
  26.  
  27.         if errmsg == "":
  28.             break
  29.         
  30.         fieldValues = g.multenterbox(errmsg, title, fieldNames, fieldValues)
  31.  
  32.     url = "http://placekitten.com/g/%d/%d" % (width, height)
  33.  
  34.     response = urllib.request.urlopen(url)
  35.     cat_img = response.read()
  36.  
  37.     filepath = g.diropenbox("请选择存放喵的文件夹")
  38.  
  39.     if filepath:
  40.         filename = '%s/cat_%d_%d.jpg' % (filepath, width, height)
  41.     else:
  42.         filename = 'cat_%d_%d.jpg' % (width, height)
  43.  
  44.     with open(filename, 'wb') as f:
  45.         f.write(cat_img)
  46.  
  47. if __name__ == "__main__":
  48.     main()

复制代码



1. 写一个登录豆瓣的客户端。
答:Python 3 对比 Python 2 有不少的改变。
在本题中:
 

  • urllib 和 urllib2 合并,大多数功能放入了 urllib.request 模块;
  • 原来的 urllib.urlencode() 变为 urllib.parse.urlencode().encode(),由于编码的关系,你还需要在后边加上 encode('utf-8');
  • cookielib 被改名为 http.cookiejar;


课堂中我们还没讲,所以这里借机会给大家简单科普一下 cookie 是什么东西:
我们说 HTTP 协议是基于请求响应模式,就是客户端发一个请求,服务端回复一个响应酱紫……
但 HTTP 协议是无状态的,也就是说客户端这会儿给服务端提交了账号密码,服务端回复验证通过,但下一秒客户端说我要访问 XXOO 资源,服务端回复:“啊??你是谁?!”

Python——论一只爬虫的自我修养2:实战

为了解决这个尴尬的困境,有人就发明出了 cookie。cookie 相当于服务端(网站)用于验证你的身份的密文。于是客户端每次提交请求的时候,服务端通过验证 cookie 即可知道你的身份信息。那么正如你所猜测的,CookieJar 是 Python 用于存放 cookie 的对象。
当然,这里已经给你提供了 Python 2 的代码,你不懂上边这些,也不影响完成作业。 

Python——论一只爬虫的自我修养2:实战

代码清单:

  1. import re
  2. import urllib.request
  3. from http.cookiejar import CookieJar
  4.  
  5. # 豆瓣的登录url 
  6. loginurl = 'https://www.douban.com/accounts/login'
  7. cookie = CookieJar()
  8. opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor)
  9.  
  10. data = {
  11.     "form_email":"your email",
  12.     "form_password":"your password",
  13.     "source":"index_nav"
  14. }
  15. data = {}
  16. data['form_email'] = '你的账号'
  17. data['form_password'] = '你的密码'
  18. data['source'] = 'index_nav'
  19.  
  20. response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))
  21.  
  22. #验证成功跳转至登录页
  23. if response.geturl() == "https://www.douban.com/accounts/login":
  24.     html = response.read().decode()
  25.     
  26.     #验证码图片地址
  27.     imgurl = re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)
  28.     if imgurl:
  29.         url = imgurl.group(1)
  30.         # 将验证码图片保存至同目录下
  31.         res = urllib.request.urlretrieve(url, 'v.jpg')
  32.  
  33.         # 获取captcha-id参数
  34.         captcha = re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)
  35.  
  36.         if captcha:
  37.             vcode = input('请输入图片上的验证码:')
  38.             data["captcha-solution"] = vcode
  39.             data["captcha-id"] = captcha.group(1)
  40.             data["user_login"] = "登录"
  41.  
  42.             # 提交验证码验证
  43.             response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))
  44.  
  45.             # 登录成功跳转至首页 '''
  46.             if response.geturl() == "http://www.douban.com/":
  47.              Print(‘登陆成功!’)