python爬虫常用的库requests,urllib,re

前言

上一节我们介绍完爬虫是啥之后,现在我们就需要来学习一下怎么样优雅快速的去爬一个网站,从而获得我们想要的信息

那怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它是一段HTML代码,加JS、CSS,如果把网页比作一个人,那么HTML便是他的骨架,JS便是他的肌肉,CSS便是它的衣服。所以最重要的部分是存在于HTML中的,下面我们就写个例子来扒一个网页下来

URLLIB 和 REQUESTS
  • urllib

    Python标准库中提供了:urllib等模块以供Http请求,但是,它的 API 太渣了。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务,下面是简单的使用urllib来进行请求数据的方法

 

import urllib.request
 
f=urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')

result = f.read().decode('utf-8')
 
# 或者
 
import urllib.request
 
req = urllib.request.Request("http://www.baidu.com")
response = urllib.urlopen(req)
print(response.read().decode('utf-8'))

  


在这里,我们需要注意的是,我们更推荐大家使用第二种方法,两种方法请求的结果都一样,只不过第二种中间多了一个request对象,为啥要这样子,因为在构建请求时还需要加入好多内容,因此通过构建一个request,服务器响应请求得到应答,这样显得逻辑上清晰明确是的,你没有看错,你没有看错,就这样,简简单单的使用urllib库中的request方法,我们就可以将别人家网站的源代码给扒了过来

比如说加入User-Agent参数到请求头,就可以使用如下方式

import urllib.request
 
req = urllib.request.Request('http://www.example.com/')
 
req.add_header("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0")
 
r = urllib.request.urlopen(req)
 
result = f.read().decode('utf-8')


注:更多见Python官方文档:https://docs.python.org/3.5/library/urllib.request.html#module-urllib.request
 

  • requests

Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得进行网络请求时,变得美好了许多,而且使用Requests可以轻而易举的完成浏览器可有的任何操作

1)安装模块

pip3 install requests

2) 初次使用

来个小栗子,活跃一下气氛

import requests
 
r = requests.get('http://www.shangzekai.xyz')
print type(r)
print r.status_code # 服务器返回状态码
print r.encoding # 使用的编码
print r.text # 返回的内容


我们发现,初次使用requests库,简洁大方,确实方便了许多,生活从此也变得美好了起来,继续接着深入了解
 

3) 基本方法

  • get请求
# 1、无参数实例
 
import requests
ret = requests.get('https://github.com/timeline.json')
 
print(ret.url)
print(ret.text)
 
 
# 2、有参数实例
import requests
 
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)
 
print(ret.url)
print(ret.text)
 
# 3、解析json
 
import requests
import json
 
response = requests.get("http://httpbin.org/get")
print(type(response.text))
print(response.json())
print(json.loads(response.text))
print(type(response.json()))
 
 
# 4、添加headers
 
import requests
 
response = requests.get("https://www.zhihu.com/explore")
print(response.text)
 
此时,我们需要加上一些头信息,来模拟浏览器的登录
 
import requests
 
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get("https://www.zhihu.com/explore", headers=headers)
print(response.text)


post请求

# 1、基本POST实例
import requests
# 当headers为application/content的时候,请求实例如下:
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
print(ret.text)
print(type(response.headers), response.headers)
print(type(response.cookies), response.cookies)
print(type(response.url), response.url)
print(type(response.history), response.history)
# 2、发送请求头和数据实例
import json
import requests
url = 'http://httpbin.org/post'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
# 当headers为application/json的时候,请求示例如下:
ret = requests.post(url, data=json.dumps(payload), headers=headers)
print(ret.text)

  

注意:

  1. get和post请求两者的区别在于,get请求方法参数只有params,而没有data参数,而post请求中两者都是有的

 

100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('already_reported',),
226: ('im_used',),
 
# Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('permanent_redirect',
'resume_incomplete', 'resume',), # These 2 to be removed in 3.0
 
# Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
421: ('misdirected_request',),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
425: ('unordered_collection', 'unordered'),
426: ('upgrade_required', 'upgrade'),
428: ('precondition_required', 'precondition'),
429: ('too_many_requests', 'too_many'),
431: ('header_fields_too_large', 'fields_too_large'),
444: ('no_response', 'none'),
449: ('retry_with', 'retry'),
450: ('blocked_by_windows_parental_controls', 'parental_controls'),
451: ('unavailable_for_legal_reasons', 'legal_reasons'),
499: ('client_closed_request',),
 
# Server Error.
500: ('internal_server_error', 'server_error', '/o\\', '✗'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
511: ('network_authentication_required', 'network_auth', 'network_authentication')

  

    4) 模拟登陆

# 1. 首先如何获取cookie
 
import requests
response = requests.get('http://www.baidu.com')
print(response.cookies)
 
for key,value in response.cookies.items():
print(key + '=' + value)
 
# 2. 会话登录
import requests
 
## 表示设置一个cookie
requests.get('http://www.httpbin.org/cookies/set/123456789')
## 然后获取网站的cookie
res = requests.get('http://www.httpbin.org/cookies')
print(res.text)
 
打印,我们发现没有数据,因为上面的两行代码,就相当于两个浏览器进行访问,因此不可能获取到第一次cookie访问的信息
 
因此,我们采用如下的方法进行模拟登陆
 
s = requests.Session()
requests.get('http://www.httpbin.org/cookies/set/123456789')
res = requests.get('http://www.httpbin.org/cookies')
print(res.text)
 
最终,我们采用上述的方法,获取到了最终的cookie的值,获取该值之后,我们可以拿着个cookie来进行登录了

  5) SSL设置

import requests
from requests.packages import urllib3
urllib3.disable_warnings()
res = requests.get('http://www.12306.cn',verify=False)
print(res.status_code)
 
 
import requests
 
response = requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key'))
print(response.status_code)

  

  • 其他请求
requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
 
# 以上方法均是在此方法的基础上构建
requests.request(method, url, **kwargs)

  

6) 代理设置

import requests
 
proxies = {
"http": "http://127.0.0.1:9743",
"https": "https://127.0.0.1:9743",
}
 
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

有密码的设置

import requests
 
proxies = {
"http": "http://user:password@127.0.0.1:9743/",
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

  


7)、超时时间设置

import requests
from requests.exceptions import ReadTimeout
try:
response = requests.get("http://httpbin.org/get", timeout = 0.5)
print(response.status_code)
except ReadTimeout:
print('Timeout')

  

 


8)、异常处理

import requests
from requests.exceptions import ReadTimeout, ConnectionError, RequestException
try:
response = requests.get("http://httpbin.org/get", timeout = 0.5)
print(response.status_code)
except ReadTimeout:
print('Timeout')
except ConnectionError:
print('Connection error')
except RequestException:
print('Error')

  

  • 常见实例

1) 检测QQ是否在线

 

import urllib
import requests
from xml.etree import ElementTree as ET
 
# 使用内置模块urllib发送HTTP请求,或者XML格式内容
"""
f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=493133139')
result = f.read().decode('utf-8')
"""
 
 
# 使用第三方模块requests发送HTTP请求,或者XML格式内容
r = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=493133139')
result = r.text
 
# 解析XML格式内容
node = ET.XML(result)
 
# 获取内容
if node.text == "Y":
print("在线")
else:
print("离线")

  


2) 查看火车停靠信息 

import urllib
import requests
from xml.etree import ElementTree as ET
 
# 使用内置模块urllib发送HTTP请求,或者XML格式内容
"""
f = urllib.request.urlopen('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result = f.read().decode('utf-8')
"""
 
# 使用第三方模块requests发送HTTP请求,或者XML格式内容
r = requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result = r.text
 
# 解析XML格式内容
root = ET.XML(result)
for node in root.iter('TrainDetailInfo'):
print(node.find('TrainStation').text,node.find('StartTime').text,node.tag,node.attrib)

  

 


1.正则表达式的概念
正则表达式

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑

正则表达式是用来匹配字符串非常强大的工具,在其他编程语言中同样有正则表达式的概念,Python同样不例外,利用了正则表达式,我们想要从返回的页面内容提取出我们想要的内容就易如反掌了

正则表达式的大致匹配过程是:

1.依次拿出表达式和文本中的字符比较,
2.如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。
3.如果表达式中有量词或边界,这个过程会稍微有一些不同

2.常见的正则表达式符号
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾
 
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall("ab+","abcdabbbba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|' 匹配|左或|右的字符,re.findall("abc|ABC","ABCBabcCD")结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
 
 
'\A' 只从字符开头匹配
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9
'\D' 匹配非数字
'\w' 匹配[A-Za-z0-9]
'\W' 匹配非[A-Za-z0-9]
's' 匹配空白字符空格、\t、\n、\r
 
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}

  

常见的使用方法

re.findall 把所有匹配到的字符放到列表中,以列表中的元素返回

findall(pattern, string, flags=0)

  

print(re.findall('\d+','one1two2three3four4'))

  

Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符;3.贪婪模式和非贪婪模式

非贪婪则相反,总是尝试匹配尽可能少的字符
但有的时候,我们并不是想要贪婪模式,那怎么办?

非常简单,只需要在”*”,”?”,”+”,”{m,n}”后面加上?,使贪婪变成非贪婪



s="This is a number 234-235-22-423" 
r=re.findall(".+(\d+-\d+-\d+-\d+)",s) print(r) #输出 '4-235-22-423' r=re.findall(".+?(\d+-\d+-\d+-\d+)",s) print(r)
# 输出 '234-235-22-423'

  

正则表达式模式中使用到通配符,那它在从左到右的顺序匹配时,会尽量“抓取”满足匹配最长字符串,在我们上面的例子里面,“.+”会从字符 串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,而“\d+”只需一位字符就可以匹配,所以导致它只匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符

解决方式:非贪婪操作符“?”,这个操作符可以用在”*”,”+”,”?”的后面,要求正则匹配的越少越好

再来感受一下,贪婪和非贪婪模式的风骚

re.findall(r"aa(\d+)","aa2343ddd")
['2343']
re.match(r"aa(\d+?)","aa2343ddd").group(1)
'2'


4.Python的多行匹配和点任意匹配
 

r=re.complile(pattern,re.M)
re.M(re.MULTILINE):多行模式,改变’^’和’$‘的行为,即^ $标志将会匹配每一行

 


re.findall(r"^a(\d+)b","a213b\na2345b\na234b") 
['213'] re.findall(r"^a(\d+)b","a213b\na2345b\na234b",re.M) ['213', '2345', '234'] re.findall(r"a(\d+)b","a213b\na2345b\na234b") #如果没有^标志,无需re.M ['213', '2345', '234']

  

re.S(re.DOTALL):点任意匹配模式

元字符“.”在默认模式下,匹配除换行符外的所有字符。在DOTALL模式下,匹配所有字符,包括换行符

 

re.findall(r".","\n",re.S)   
['\n']

  

5.常见的正则表达式
IP: 
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$ 手机号: ^1[3|4|5|8][0-9]\d{8}$ 邮箱: [a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+
 
6.一个简单的抓取网页分析的案例
 1 import requests
 2 import re
 3 hds=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},
 4     {'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},
 5     {'User-Agent':'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'},
 6     {'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0'},
 7     {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/44.0.2403.89 Chrome/44.0.2403.89 Safari/537.36'},
 8     {'User-Agent':'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'},
 9     {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'},
10     {'User-Agent':'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'},
11     {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'},
12     {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'},
13     {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'},
14     {'User-Agent':'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11'},
15     {'User-Agent':'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11'}]
16 def get_page(url):
17     headers = hds[random.randint(0,len(hds)-1)]
18     response = requests.get(url, headers = headers)
19     try:
20         if response.status_code == 200:
21             res = response.text
22             return res
23         return None
24     except Exception as e:
25         print(e)
26 '''
27 <div class="board-item-content">
28     <div class="movie-item-info">
29         <p class="name"><a href="/films/1203" title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
30         <p class="star">
31             主演:张国荣,张丰毅,巩俐
32         </p>
33         <p class="releasetime">上映时间:1993-01-01(中国香港)</p>
34     </div>
35     <div class="movie-item-number score-num">
36         <p class="score"><i class="integer">9.</i><i class="fraction">6</i></p>
37     </div>
38 </div>
39 '''
40 def get_movie(html):
41     partten = '<p.*?><a.*?>(.*?)</a></p>.*?<p.*?>(.*?)</p>.*?<p.*?>(.*?)</p>'
42     items = re.findall(partten, html, re.S)
43     #print((items))
44     return items
45 def write_file(items):
46     fileMovie = open('movie.txt', 'w', encoding='utf8')
47     try:
48         for movie in items:
49             fileMovie.write('电影排名:' + movie[0] + '\r\n')
50             fileMovie.write('电影主演:' + movie[1].strip() + '\r\n')
51             fileMovie.write('上映时间:' + movie[2] + '\r\n\r\n')
52         print('文件写入成功...')
53     finally:
54         fileMovie.close()
55 def main(url):
56     html = get_page(url)
57     items = get_movie(html)
58     write_file(items)
59     
60 if __name__ == '__main__':
61     url = "http://maoyan.com/board/4"
62     main(url)

 

 

最终的结果:
maoyan.png

 
posted @ 2018-11-13 15:54  rianley  阅读(535)  评论(0)    收藏  举报