Python爬虫学习笔记3:基本库的使用
学习参考:Python3网络爬虫开发实战
3.1 urllib
官方文档链接为 : https://docs.python.org/3/library/urllib.html
3.1.1 发送请求
1. urlopen()
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')
# print(response.read().decode('utf-8'))
print(type(response)) # 查看输出的响应类型
'''
它是一个 HTTPResposne类型的对象,主要包含 read()、 readinto()、 getheader(name)、
getheaders()、 fileno()等方法,以及 msg、 version、 status、 reason、 debuglevel、 ιlosed等属性
'''
print(response.status) # 返回结果状态码
print(response.getheaders()) # 响应头信息
print(response.getheader('Server')) # 调用 getheader() 方法并传递一个参数 Server 获取了响应头中的 Server 值
print(response.getheader('Set-Cookie'))
获取下来的结果:
• data参数
data 参数是可选的 。 如果要添加该参数,并且如果它是字节流编码格式的内容,即 bytes 类型, 则需要通过 bytes()方法转化。 另外,如果传递了这个参数,则它的请求方式就不再是 GET方式,而 是 POST方式
# data参数 import urllib.parse import urllib.request data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf8') #bytes()方法,该方法的第一个参数需要是 str (字符串)类型,需要用 urllib.parse 模 块里的 urlencode()方法来将参数字典转化为字符串;第二个参数指定编码格式,这里指定为 utf8 # 用str转,405 错误 response = urllib.request.urlopen('http://httpbin.org/post',data=data) print(response.read()) print(response.status)
还是报405错误,提示方法不被允许
• timeout参数
timeout参数用于设置超时时间,单位为秒,意思就是如果请求超出了设置的这个时间, 还没有得 到响应 , 就会抛出异常。 如果不指定该参数 ,就会使用全局默认时间 。 它支持 HTTP, HTTPS、 FTP 请求
#timeout参数 # import urllib.request # # response = urllib.request.urlopen('http://www.baidu.com',timeout=1) # 超过一秒没反应就跳出异常 # print(response.status) # print(response.read())
import urllib.request
import urllib.error
import socket
try:
response = urllib.request.urlopen('http://www.baidu.com',timeout=0.01) # 超过一秒没反应就跳出异常
print(response.status)
print(response.read())
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout): # 判断一个对象是否是一个已知的类型
print('TIME OUT')
2. Request
# request # import urllib.request # # request = urllib.request.Request('http://www.baidu.com') # response = urllib.request.urlopen(request) # print(response.read()) ''' Request参数 URL data:data 如果要传,必须传 bytes (字节流)类型的 。 如果它是字典,可以先用 urllib.parse模块里的 urlencode()编码。 headers:是一个字典,通过 headers参数直 接构造,也可以通过调用请求实例的 add_header()方法添加.通过修改 User-Agent 来伪装浏览器,默认的 User-Agent 是Python-urllib origin_req_host:请求方的 host名称或者 IP地址 unverifiable: ''' import urllib.request import urllib.parse url = 'http://www.baidu.com' headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36', 'Host':'http://www.baidu.com' } dict = { 'name':'abcd' } data = bytes(urllib.parse.urlencode(dict),encoding='utf-8') req = urllib.request.Request(url=url,headers=headers, method='POST') response = urllib.request.urlopen(req) print(response.read().decode('utf-8'))
3. 高级用法
Handler 各种处理器,有 专门处理登录验证的,有处理 Cookies 的,有处理代理设置的 。
https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler
urllib .request 模块里的 BaseHandler类,它是所有其他 Handler 的父类,它提 供了最基本的方法,例如 default_open()、 protocol_request()等
·验证
需要登陆验证的网址,借助HTTPBasicAuthHandler
# 验证 from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler,build_opener from urllib.error import URLError username = 'username' password = 'password' url = 'http://localhost:5000' p = HTTPPasswordMgrWithDefaultRealm() # 实例化 p.add_password(None,url,username,password) # 调用类里面的方法 auth_handler = HTTPBasicAuthHandler(p) opener = build_opener(auth_handler) try: result = opener.open(url) html = result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)
·代理
# 代理 # from urllib.error import URLError # from urllib.request import ProxyHandler, build_opener # # proxy_handler = ProxyHandler({ # 'http':'http://', # 'https':'https://' # }) # opener = build_opener(proxy_handler) # try: # response = opener.open('http://www.baidu.com') # print(response.read().decode('utf-8')) # except URLError as e: # print(e.reason)
• Cookies
# cookie # import urllib.request # import http.cookiejar # # cookie = http.cookiejar.CookieJar() # handler = urllib.request.HTTPCookieProcessor(cookie) # opener = urllib.request.build_opener(handler) # response = opener.open('http://www.baidu.com') # for item in cookie: # print(item.name + "=" + item.value) # 保存cookies到文件,使用MozillaCookieJar # import urllib.request # import http.cookiejar # # filename = 'cookie.txt' # cookie = http.cookiejar.MozillaCookieJar(filename) # handler = urllib.request.HTTPCookieProcessor(cookie) # opener = urllib.request.build_opener(handler) # response = opener.open('http://www.baidu.com') # cookie.save(ignore_discard=True,ignore_expires=True) # 读取保存的cookie文件 # import urllib.request # import http.cookiejar # # cookie = http.cookiejar.MozillaCookieJar() # cookie.load('cookie.txt',ignore_expires=True,ignore_discard=True) # handler = urllib.request.HTTPCookieProcessor(cookie) # opener = urllib.request.build_opener(handler) # response = opener.open('http://www.baidu.com') # print(response.read().decode('utf-8'))
3.1.2 处理异常
1 URLError
RLError类来自 urllib库的 error模块,它继承自 OSError类,是 error异常模块的基类,由 request 模块生的异常都可以通过捕获这个类来处理
2. HTIPError
它是 URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败等。它有如下 3个属性.
3.1.3 解析链接
urllib库里还提供了parse模块,它定义了处理URL的标准接口,例如实现URL各部 分的抽取、合并以及链接转换.
1. urlparse()
# urlparse from urllib.parse import urlparse result = urlparse("http://www.baidu.com/index.html;user?id=S#comment") print(result)
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=S', fragment='comment')
返回结果是一个 ParseResult 类型的对象,它包含 6个部分,分别是 scheme、 netloc、path、 params、 query和 fragment.
://前面的就是 scheme,代表协议;第一个/符号前面便是 netloc,即域名,后面是 path,即访 问路径;分号;前面是 params,代表参数;问号?后面是查询条件 query, 一般用作 GET类型的 URL;
井号#后面是锚点,用于直接定位页面内部的下拉位置.
scheme://netloc/path ;params?query#fragment
urllib.parse.urlparse(urlstring, scheme=”, allow_fragments=True)
2. urlunparse()
3. urlsplit()
4. urlunsplit()
5. urljoin()
6. urlencode()
# urlencode() from urllib.parse import urlencode params = { 'name':'germy', 'age':22 } base_url = 'http://www.baidu.com?' url = base_url + urlencode(params) print(url)
# http://www.baidu.com?name=germy&age=22
7. parse_qs() 反序列化,字典类型
8. parse_qsl() 反序列化,元祖类型
9. quote()
内容转化为 URL 编码的格式 。 URL 中带有中文参数时,有时可能会导致乱码的问 题,此时用这个方法可以将巾文字符转化为 URL编码
# quote from urllib.parse import quote keyword = '中国' URL = 'http://www.baidu.com/s?wd=' + quote(keyword) print(URL)
# http://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
10. unquote() 解码
3.1.4 分析 Robots协议
1. Robots 协议
来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。它通常是一个叫作 rob。“.txt 的文本文件,一般放在网站的根目录下
3. robotparser
解析 robots.txt, 提供了一个 类 RobotFileParser,可以根据某网站的 robots.txt文件来判断一个爬取爬虫是否有权限来爬取这个 网页
3.2 使用 requests
其他的请求类型依然可 以用一句话来完成 .
如果要附加额外的信息,利用 params这个参数
如果想直接 解析返回结果,得到一个字典格式的话,可以直接调用 json()方法
·抓取网页
import requests import re # r = requests.get('http://www.baidu.com') # r = requests.post('http://www.baidu.com') headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36' } r = requests.get("https://www.zhihu.com/explore",headers=headers) pattern = re.compile('explore-feed.*?question_link.*?>(.*?)</a>',re.S) titles = re.findall(pattern,r.text) print(titles)
·抓取二进制数据
import requests r = requests.get("https://github.com/favicon.ico") with open('favicon.ico','wb') as f: f.write(r.content)
3.2.2 高级用法
1. 文件上传
# import requests # # files = {'file': open('favicon.ico','rb')} # r = requests.post('http://httpbin.org/post',files = files) # print(r.text)
2. Cookies
import requests r = requests.get('http://www.baidu.com') print(r.cookies) for key, value in r.cookies.items(): print(key + "=" + value)
3 会话维持
维持同一个会话 , 也就是相当于打开一个新的浏览器选项 卡而不是新开一个浏览器。 但是我又不想每次设置 cookies,可以通过设置session来满足。
# 会话保持 import requests s = requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') r = s.get('http://www.httpbin.org/cookies') print(r.text)
'''
{
"cookies": {
"number": "123456789"
}
}
'''
3.3 正则表达式
# 正则表达式 # import re # # content = "Hello 123 4567 World_This is a Regex Demo" # result = re.match('^Hello\s\d{3}\s\d{4}\s\w{10}',content) # print(result) # print(result.group()) # print(result.span())
·修饰 符
match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败
search(),它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结 果 。
findall()方法 该方法会搜索整 个字符串,然后返回匹配正则表达式的所有内容
sub() 替换文本
compile() 将正则字符串编译成正 则表达式对象,以便在后面的匹配中复用
3.4 抓取猫眼电影排行
爬取猫眼排名100的电影信息
import requests import re import json def get_one_page(url): headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36' } response = requests.get(url, headers=headers) if response.status_code == 200: return response.text return None def parse_one_page(html): pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)@.*?".*?name"><a' + '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>' + '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S) items = re.findall(pattern,html) for item in items: yield { 'index':item[0], 'image':item[1], 'title':item[2].strip(), 'actor':item[3].strip()[3:] if len(item[3])>3 else '', 'time':item[4].strip()[5:] if len(item[4])>5 else '', 'score':item[5].strip() + item[6].strip() } def write_to_file(content): with open('result1.txt','a', encoding='utf-8') as f: print(type(json.dumps(content))) f.write(json.dumps(content,ensure_ascii=False)+'\n') def main(offset): url = 'http://maoyan.com/board/4?offset=' + str(offset) html = get_one_page(url) for item in parse_one_page(html): write_to_file(item) if __name__ == "__main__": for i in range(10): main(offset=i * 10)