微博话题爬取与存储分析(上)

大数据社会下数据就是黄金,新浪微博作为一个国内网络社交早就意识到这一点,本着资本家和商人的心态给你提供的开放API接口只可以获得少量无关紧要的数据(想要数据,money来换),对比国外Twitte等社交平台会提供一些数据接口供研究人员获取大量研究数据。那我们GEEK的口号是,凡是网上能显示数据的朕兼“可取”(v_v…为什么加个引号呢,因为虽然出于技术角度是都可取得,但出于道德方面考虑也要尊重数据作者的规约)( 本文原创,未授权不得转载。)

看点

01

一步步教你数据采集

引言

本文基于python以新浪微博为数据平台,从数据采集、关键字提取、数据存储三个角度,用最简单的策略来挖掘我们的“黄金”。

有爬虫基础的人可以直接跳过数据采集部分看“上海租房”话题挖掘实战项目,项目地址https://github.com/luzhijun/weiboSA(目前已更新豆瓣小组爬取)。

数据采集

使用python是因为代码简洁,虽然计算比java和c慢很多,但数据采集时间开销大部分是IO部分的,你愿意每次用java或者c写效率也提高不到哪去。

数据采集基本用爬虫机器人,原理谁都会,google就是靠他发家致富走上人生巅峰的。下面介绍常用来做爬虫的几个库。

Urllib

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

import urllib2
response = urllib2.urlopen("http://www.baidu.com")
print response.read()

结果就和在Chrome等浏览器中右键查看源码一样的内容,urllib2是python内置库,简化了httplib的用法(urllib2.urlopen相当于Java中的HttpURLConnection)。有2那肯定有urllib啊,urllib2可以接受一个Request类的实例来设置URL请求的headers,但urllib仅可以接受URL。这意味着,你不可以伪装你的User Agent字符串等。urllib2在python3.x中被改为urllib.request。 接下来用urllib2伪装iphone 6浏览,模拟浏览器发送GET请求。

req = request.Request('http://www.douban.com/')req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')with request.urlopen(req) as f:
    print('Status:', f.status, f.reason)
    print('Data:', f.read().decode('utf-8'))

结果会返回移动版的源码信息。

<link rel="apple-touch-icon-precomposed" href="https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/screen_icon.png"/>  
<meta name="format-detection" content="telephone=no"/>

如果想要以post方式提交,只要在Request中附加data字段就可以,下面附加用户名密码登录新浪博客。

#我们模拟一个微博登录,先读取登录的邮箱和口令,然后按照weibo.cn的登录页的格式以username=xxx&password=xxx的编码传入:from urllib import parseprint('Login to weibo.cn...')email = input('Email: ')passwd = input('Password: ')login_data = parse.urlencode([
    ('username', email),
    ('password', passwd),
    ('entry', 'weibo'),
    ('client_id', ''),
    ('savestate', '1'),
    ('ec', ''),
    ('pagerefer', 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F')])req = request.Request('https://passport.weibo.cn/sso/login')req.add_header('Origin', 'https://passport.weibo.cn')req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')with request.urlopen(req, data=login_data.encode('utf-8')) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))

其中Origin和referer字段是反“反盗链”,就是检查你发送请求的header里面,referer站点是不是他自己。

Cookielib

爬虫被封的一个依据就是重复IP,因此可以为爬虫设置不同代理IP。此外有些网站需要cookie才能查看,所谓Cookie,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容是不允许的。那么我们可以利用Urllib2库保存我们登录的Cookie,然后再抓取其他页面就达到目的了。

cookielib模块的主要作用是提供可存储cookie的对象,以便于与urllib2模块配合使用来访问Internet资源。Cookielib模块非常强大,我们可以利用本模块的CookieJar类的对象来捕获cookie并在后续连接请求时重新发送,比如可以实现模拟登录功能。该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。

它们的关系:CookieJar–派生->FileCookieJar –派生–>MozillaCookieJar和LWPCookieJar

from urllib import requestfrom http.cookiejar import CookieJarcookie=CookieJar()cookie_support= request.HTTPCookieProcessor(cookie)#cookie处理器opener = request.build_opener(cookie_support)opener.open('http://www.baidu.com')for item in cookie:
    print(item.name,':',item.value)

结果:

BAIDUID : E4DECD4AF63915B9AFF5AC28951A3DAA:FG=1
BIDUPSID : E4DECD4AF63915B9AFF5AC28951A3DAA
H_PS_PSSID : 1437_18241_17944_21079_18559_21454_21406_21377_21191_21321
PSTM : 1477631558
BDSVRTM : 0
BD_HOME : 0

这里使用默认的CookieJar 对象,如果要将Cookie保存起来,可以使用FileCookieJar类和其子类中的save方法,加载就用load方法。

写脚本从指定网站抓取数据的时候,免不了会被网站屏蔽IP。所以呢,就需要有一些IP代理。随便在网上找了一个提供免费IP的网站西刺做IP抓取。观察可以发现有我们需要的信息的页面url有下面的规律:www.xicidaili.com/nn/+页码。可是你如果直接通过get方法访问的话你会发现会出现500错误。原因其实出在这个规律下的url虽然都是get方法获得数据,但都有cookie认证,另外还有反外链等,下面例子用来获得西刺的cookie。

headers=[('User-Agent','Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25'),
    ('Host','www.xicidaili.com'),
    ('Referer','http://www.xicidaili.com/n')]def getCookie()
    cookie=CookieJar()
    cookie_support= request.HTTPCookieProcessor(cookie)#cookie处理器
    opener = request.build_opener(cookie_support)
    opener.addheaders=headers
    opener.open('http://www.xicidaili.com/')
    return cookie

有了cookie就可以爬了,爬的内容怎么处理呢,介绍个SB工具—— BeautifulSoup。

BeautifulSoup

BeautifulSoup翻译叫鸡汤,现在版本是4.5.1,简称BS4,倒过来叫4SB,不过抓数据一点都不SB。提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。 关于BS的介绍和用法官方文档很详细,下面给几个”Web scraping with python”1中的例子看下BS是否好喝,可以和文档对照看。 首先你得安装了BS,然后爬取http://www.pythonscraping.com/pages/page3.html中的图片来小试牛刀。

import refrom urllib import requestfrom bs4 import BeautifulSouphtml=request.urlopen("http://www.pythonscraping.com/pages/page3.html")bs=BeautifulSoup(html,"lxml")#打印所有图片地址for pic in bs.find_all('img',{'src':re.compile(".*\.jpg$")}):
    print(pic['src'])

结果:

../img/gifts/logo.jpg
../img/gifts/img1.jpg
../img/gifts/img2.jpg
../img/gifts/img3.jpg
../img/gifts/img4.jpg
../img/gifts/img6.jpg

接上文,我们把西刺的高匿代理ip爬出来放到本地proxy.txt。

cookie=getCookie()# get the proxywith open('proxy.txt', 'w') as f:
    for page in range(1,101):
        if page%50==0:#每50页更新下cookie
            cookie=getCookie()

        url = 'http://www.xicidaili.com/nn/%s' %page
        cookie_support= request.HTTPCookieProcessor(cookie)
        opener = request.build_opener(cookie_support)
        request.install_opener(opener)

        req = request.Request(url,headers=dict(headers))
        content = request.urlopen(req)
        soup = BeautifulSoup(content,"lxml")
        trs = soup.find('table',id="ip_list").findAll('tr')
        for tr in trs[1:]:
            tds = tr.findAll('td')
            ip = tds[1].text.strip()
            port = tds[2].text.strip()
            protocol = tds[5].text.strip().
            f.write('%s://%s:%s\n' % (protocol, ip, port))

结果十五秒爬了1万条数据(与电脑环境有关),说明1页正好100条,而总页数超过1000页,也就是记录数超过10w条,如果固定用同一个cookie肯定不安全(谁会有空翻看1000页数据。。。),因此设置每爬50页更新下cookie。 有了代理地址,不一定能保证有效,可能就被封杀了,因此使用思路是把代理地址存入哈希表,验证无效的删除(看状态码),重新在表中取新的记录。 代理地址使用方式如下:

...
proxy_handler = request.ProxyHandler({'http': '123.165.121.126:81'}) #http://www.xicidaili.com/nn/2 随便找个
opener = request.build_opener(proxy_handler,cookie_handler ...各种其他handle)
...

另外推荐个神器,crawlera ,基本满足各种需要。

假如真要爬1000页,需要花150秒?好吧,好像也不多,但我要说的是可以多进程或者异步处理。多进程很好做,注意以手动维护一个HttpConnection的池,然后每次抓取时从连接池里面选连接进行连接即可(每秒几百个连接正常的有理智的服务器一定会封禁你的)。python的异步处理用到了Twisted库,却远没有同是异步模式的nodejs火,算是python中的巨型框架了,想想python的巨型框架活的不久,感兴趣的推荐看下《Twisted网络编程必备》2。关于单线程、多线程、异步有张图推荐看下。

写爬虫还要考虑其他很多问题,授权验证、连接池、数据处理、js处理等,这里有个经典爬虫框架:Scrapy,目前支持python3,支持分布式, 使用 Twisted来处理网络通讯,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。

Scrapy与Pyspider

Scrapy的入门学习参见学习Scrapy入门,对应中文文档几小时内可以快速掌握。另外国内某大神开发了个WebUI的Pyspider,具有以下特性:

  • python 脚本控制,可以用任何你喜欢的html解析包(内置 pyquery)
  • WEB 界面编写调试脚本,起停脚本,监控执行状态,查看活动历史,获取结果产出
  • 支持 MySQL, MongoDB, SQLite
  • 支持抓取 JavaScript 的页面
  • 组件可替换,支持单机/分布式部署,支持 Docker 部署
  • 强大的调度控制

从内容上讲,两者具有功能差不多,包括以上3,5,6。不同是Scrapy原生不支持js渲染,需要单独下载scrapy-splash,而PyScrapy内置支持scrapyjs;PySpider内置 pyquery选择器,Scrapy有XPath和CSS选择器,这两个大家可能更熟一点;此外,Scrapy全部命令行操作,Pyscrapy有较好的WebUI;还有,scrapy对千万级URL去重支持很好,采用布隆过滤来做,而Spider用的是数据库来去重?最后,PySpider更加容易调试,scrapy默认的debug模式信息量太大,warn模式信息量太少,由于异步框架出错后是不会停掉其他任务的,也就是出错了还会接着跑。。。从整体上来说,pyspider比scrapy简单,并且pyspider可以在线提供爬虫服务,也就是所说的SaaS,想要做个简单的爬虫推荐使用它,但自定义程度相对scrapy低,社区人数和文档都没有scrapy强,但scrapy要学习的相关知识也较多,故而完成一个爬虫的时间较长。

因为比较喜欢有完整文档的支持,所以后面主要用Scrapy,简要说下Scrapy运行流程。

  • 首先,引擎从调度器中取出一个链接(URL)用于接下来的抓取
  • 引擎把URL封装成一个请求(Request)传给下载器,下载器把资源下载下来,并封装成应答包(Response)
  • 然后,爬虫解析Response
  • 若是解析出实体(Item),则交给实体管道进行进一步的处理。
  • 若是解析出的是链接(URL),则把URL交给Scheduler等待抓取

根据scrapy文档描述,要防止scrapy被禁用,主要有以下几个策略。

  • 动态设置user agent
  • 禁用cookies
  • 设置延迟下载
  • 使用 Google cache
  • 使用IP地址池( Tor project 、VPN和代理IP)
  • 使用 Crawlera

由于Google cache基于你懂的原因不可用,其余都可以利用,Crawlera的分布式下载,我们可以在下次用一篇专门的文章进行讲解。下面主要从动态随机设置user agent、禁用cookies、设置延迟下载和使用代理IP这几个方式入手。

自定义中间件

Scrapy下载器通过中间件控制的,要实现代理IP、user agent切换可以自定义个中间件。 在项目下创建(如何创建项目,使用scrapy start yourProject命令,参考文档)好项目后,在里面找到setting.py文件,先把agents和代理ip放到setting.py中(代理ip较少情况下这样做,较多的话还是放到数据库中去,方便管理),设置中间件名字MyCustomSpiderMiddleware和优先级。

USER_AGENTS = [
	"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
	"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
	"Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
	"Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
	"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
	"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
	"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
	"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
	"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
	"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
	"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
	"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
	"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
	"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
	"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
	"Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",]PROXIES = [
	{'ip_port': '111.11.228.75:80', 'user_pass': ''},
	{'ip_port': '120.198.243.22:80', 'user_pass': ''},
	{'ip_port': '111.8.60.9:8123', 'user_pass': ''},
	{'ip_port': '101.71.27.120:80', 'user_pass': ''},
	{'ip_port': '122.96.59.104:80', 'user_pass': ''},
	{'ip_port': '122.224.249.122:8088', 'user_pass': ''},]# 禁用cookoe (enabled by default)COOKIES_ENABLED = False#设置下载延迟DOWNLOAD_DELAY = 1# 下载中间件# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.htmlDOWNLOADER_MIDDLEWARES = {
    'weiboZ.middlewares.MyCustomDownloaderMiddleware': 543,}

middlewares/MyCustomDownloaderMiddleware.py

import randomimport base64from settings import PROXIESclass RandomUserAgent(object):
	"""Randomly rotate user agents based on a list of predefined ones"""
	def __init__(self, agents):
		self.agents = agents
	@classmethod
	def from_crawler(cls, crawler):
		return cls(crawler.settings.getlist('USER_AGENTS'))
	def process_request(self, request, spider):
		#随机选个agent
		request.headers.setdefault('User-Agent', random.choice(self.agents))class ProxyMiddleware(object):
	def process_request(self, request, spider):
		proxy = random.choice(PROXIES)
		if proxy['user_pass'] is not None:
			request.meta['proxy'] = "http://%s" % proxy['ip_port']
			encoded_user_pass = base64.encodestring(proxy['user_pass'])
			request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass
		else:
			request.meta['proxy'] = "http://%s" % proxy['ip_port']

看点

02

互联网道德和规约

道德与规约

当你准备爬某个网站的时候,首先应该先看下该网站有没有robots.txt。robots.txt是1994年出现的,也称为机器人排除标准(Robots Exclusion Standard),网站管理员不想某些内容被爬到的时候可以再该文件中注明。robots.txt虽然有主流的语法格式,但是各大企业标准不一,没有别人可以阻止你创建自己版本的robots.txt,但这些robots.txt不应该因为不符合主流而不被遵守。一般文件字段包含:User-agent,Allow,Disallow分别代表搜索机器人允许看和不许看的内容。

之前看新闻说今年4月大众点评把百度给告了,请求法院判令两被告停止不正当竞争行为,共同赔偿汉涛公司经济损失9000万元和为制止侵权行为支出的45万余元,并刊登公告、澄清事实消除不良影响。有用百度地图的应该知道这个(最近百度高德开撕,又在黑百度了~~~),定位完毕会显示附近商家和点评信息,来看下大众点评网的robots.txt. 光看

User-agent: *
…
Disallow: /shop//rank_p
…

就知道不允许任何企业和个人爬他家的商店评分数据,更何况其他更具有价值的数据呢,数据是黄金,要求赔偿9000万元对百度来说不算多,但百度回应内容大众点评网的robots协议面向百度等搜索引擎开放,百度地图抓取大众点评网的内容正是在robots.txt允许的情况下。通常业内习惯上没有被不允许的就是允许的,也就是说网站的关键信息可以帮助SEO优化的这个不能被禁止哟,不然你就没头条了,看人家竞争对手爱帮网倒是单独被列出来全面封杀了,因为其实力太弱,没有商业合作价值。就算这样我也没看出允许百度抓点评的用户评论数据,难道说点评网之前没robots.txt?人家不傻!百度挖了人家数据还叫嚣着遵守Robots协议,(其实他完全可以偷偷摸摸抓了数据自己私下研究,却要直接在百度地图上显示出来,这是要把数据价值榨干啊,够霸道)好比把人打了顿理直气壮地说你瞅啥一样,太野蛮了。。。

说多了,来看下新浪微博的Robots协议。明确规定了Sitemap: http://weibo.com/sitemap.xml 中列出的内容不允许被百度、360、谷歌、搜狗、微软必应、好搜、神马查看,后面还注明了Disallow: User-agent: * Disallow: /,也就是说前面是单独列出的,理论上这些数据不允许任何机构和个人爬取。这些是啥数据呢,movie和music数据,那你放心好了,微博文本数据可以爬了,但人家也不傻,可以显示的微博信息是有限制的,不可能所有数据库的数据都显示出来。

未完待续

下篇我们介绍项目实战,请关注!

文末:文章来源机器学习和自然语言处理(ID:datathinks),作者:机器学习和自然语言处理。本公众号旨在技术传播与分享,未经授权不能转载发布。

原文发布于微信公众号 - 机器学习和自然语言处理(datathinks)

原文发表时间:2017-12-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏极客猴

100行代码爬取全国所有必胜客餐厅信息

当我刚接触 Python 时,我已经被 Python 深深所吸引。Python 吸引我的地方不仅仅能用其编写网络爬虫,而且能用于数据分析。我能将大量的数据中以图...

1111
来自专栏哲学驱动设计

产品前端重构(TypeScript、MVC框架设计)

最近两周完成了对公司某一产品的前端重构,本文记录重构的主要思路及相关的设计内容。 公司期望把某一管理类信息系统从项目代码中抽取、重构为一个可复用的产品。该系统的...

2528
来自专栏FSociety

Python爬取猫眼「碟中谍」全部评论

评论算保存完了,近期会再做一个关于此次数据的可视化分析。另外阿汤哥真心太帅了,全程打肾上腺素,各位还没去看的赶紧~

730
来自专栏一个爱吃西瓜的程序员

爬取许嵩的所有微博并存入MongoDB

我很喜欢许嵩的音乐,我以前基本上他的每首歌都会唱,比如《素颜》、《灰色头像》、《玫瑰花的葬礼》、《清明雨上》、《庐州月》等等,打开播放器,基本上都是循环播放许嵩...

772
来自专栏程序猿DD

极大提高工作效率的几十种神兵利器

来源:https://www.liutf.com/posts/3720794851.html

2033
来自专栏Golang语言社区

高并发服务器的设计--架构与瓶颈的设计

做架构设计,难免有时候被人问及系统的瓶颈在哪,那首先来了解下什么是瓶颈? 打个形象的比方,人的嘴巴可以吞下一整个面包,但是却咽不下去,因为食管不给力,它比较细,...

6228
来自专栏Cloud Native - 产品级敏捷

微服务架构 (五): 获取微服务数据, 生成报表

2016.8.17, 深圳, Ken Fang 架构师在设计从多个微服务取数据, 而生成报表的架构设计方案时, 往往面临著需在边界上下文 (Bounded Co...

20810
来自专栏Linyb极客之路

我珍藏的神兵利器 - 效率工具

快速启动应用+文件搜索+各种实用插件(计算器、翻译、网页快速访问等)。我的最爱,没有它我几乎半残。

2054
来自专栏程序猿

性能优化的磁盘阵列

上题讲到mysql的硬件优化的时候,有提到磁盘阵列(Redundant Arrays of Independent Disks,RAID )...

3998
来自专栏数据和云

DBA生存警示:系统级误删除案例及防范建议

编辑手记:对于资深的老DBA们,他们在漫长的职业生涯中养成了很多稀奇古怪的守则,以在复杂多变的环境中“幸存”,这源于无数血泪的教训,我曾经在《数据安全警示录》...

2864

扫码关注云+社区