
该列表不是最终版本,会不时更新。 先说两句,作为序: 一、当下,AI次泡沫正在形成中,其背后的最为深刻的主要原因在于当前计算理论的薄弱,导致现实中机器学习的有效性被人们广为认可,但机器学习(含深度学习和强化学习)的局限性却因理论缺失而完全不被了解。因此,一方面看到AI显在的优势,但另一方面却看不到潜在的劣势,于是泡沫被越吹越大(荒谬地认为只要算法更先进、数据更多,必定就会更智能,甚至是直接产生智能)。特别是对公司而言,不要以为技术能解决一切问题。如果公司是只苍蝇,那么技术就是苍蝇的翅膀,理论就是苍蝇的头脑,离开理论的沉淀,只是无脑瞎撞的苍蝇而已。 二、AGI有很多子类别或子层面,我关注的是与人脑思维等同的层面。在这个层面上,智能并不等同于计算,即存在着“图灵机失效”或“图灵机局限”的情况。如果想读我团队的硕士、博士生乃至博士后,则以下书单是必修。 通向AGI的另类书单(按顺序由浅入深排列): ----------PART 1 初阶部分----------- 1、《人工智能简史》,尼克 著,人民邮电出版社,2017-12 推荐理由:观今宜鉴古,无古不成今,以史为鉴方才知今日之症结。本书较为全面和客观地揭示了AI的发展史,可以从书中了解AI可以做什么 2、《智能的本质 人工智能与机器人领域的64个大问题》,[美] 皮埃罗·斯加鲁菲(Piero Scaruffi)著,人民邮电出版社,2017-01 推荐理由:AI还不能做什么,了解一下 3、《认知心理学:心智、研究与你的生活》,[美] 戈尔茨坦(Goldstein,E. B.) 著,中国轻工业出版社,2015-02 推荐理由:选择从人脑了解认知,而非从统计学中观察算法,是理解AGI问题的前提和基石。以此书来了解人能做什么 4、《深层学习:心智如何超越经验》,[美] 斯特兰·奥尔松(Stellan Ohlsso)著,机械工业出版社,2017-03 推荐理由:提出非单调认知变化的统合理论,说明人脑经验建构的可能性,并给出了理论框架及猜测 5、《内隐学习的争论及限制问题》,姜珊 著,上海社会科学院出版社,2017-03 推荐理由:意识活动只是大脑认知活动的很小一部分,潜意识活动实际上是意识活动的基干和底槽,内隐学习便是其中一种重要的活动。本书使用科学的手段观察内隐学习的特征 6、《认知哲学导论》,樊岳红 著,科学出版社,2018-01 推荐理由:认知哲学基本问题入门 ----------PART 2 中阶部分----------- 7、《认知科学中的当代争论》,[加] 罗伯特·J.斯坦顿 著,科学出版社,2015-10 推荐理由:认知哲学基本问题入门后,借由此书了解基本争论。目的是进行更为深层的反思 8、《精神病学》,郝伟,于欣 编,人民卫生出版社,2013-03 推荐理由:精神障碍患者的大脑也是人脑,从其某些缺陷中可以反过来观察正常人认知机制的工作原理 9、《变态心理学》,[美] 苏珊·诺伦 - 霍克西玛 著,人民邮电出版社,2017-07 推荐理由:作为对精神病学的重要补充,同时也是医学和心理学在人的认知问题上的对话和交锋 10、《意识的认知理论》,[美] 伯纳德·J.巴尔斯(Baars B.J.) 著,科学出版社,2014-01 推荐理由:心理学视角下的AGI理论 11、《Non-Axiomatic Logic: A Model Of Intelligent Reasoning》,Pei Wang 著,World Scientific,2013-05 推荐理由:一个完整的AGI理论及其计算机系统实现(NARS) 12、《Theoretical Foundations of Artificial General Intelligence》,Pei Wang, Ben Goertzel 编,Atlantis Press,2012-09 推荐理由:了解一下其他各派AGI理论,看看是否能够取长补短 ----------PART 3 高阶部分----------- 13、《Haskell函数式程序设计》,[英] 理查德·伯德 著,机械工业出版社,2016-03 推荐理由:轮到自己亲自动手了,编程就像make love,你不能找别人去替你完成。控制部分可用Haskell 14、《Neo4j实战》,[英] 阿列克萨·武科蒂奇(AleksaVukotic) 等 著,机械工业出版社,2016-04 推荐理由:记忆部分可用Neo4j 15、《学前教育学》,梁志燊 著,北京师范大学出版社,2014-01 推荐理由:AGI可用性和商用化的第一步,解决常识问题 16、《发展心理学 从生命早期到青春期》,[美] 黛安娜·帕帕拉,萨莉·奥尔茨,露丝·费尔德曼 著,人民邮电出版社,2013-09 推荐理由:AGI可用性和商用化的第二步,建立主体健全的基本经验结构 17、《剑桥学习科学手册》,[美] R.基思·索耶 著,教育科学出版社,2010-04 推荐理由:AGI可用性和商用化的第三步,解决和发展主体解决专用问题的能力
怀揣梦想背对晚霞化入黑暗静待朝阳作为第一个暮光之人继续在质疑与否定中微笑着看着前方 2018年5月6日,下午,于榴花
新入门Python数据分析的硕士、博士们,请拿取参考: 1、桌面软件开发WxPython、Tkinler2、网站开发Django、Web2py、Web.py、Zope2 [Python + HTML + MySQL(or PostgreSQL)]3、游戏开发Pygame、cocos2d4、科学计算Pandas:Python数据分析库NumPy:一个定义了数值数组和矩阵类型和它们的基本运算的语言扩展SciPy:另一种使用NumPy来做高等数学、信号处理、优化、统计和许多其它科学任务的语言扩展Matplotlib:绘图的语言扩展5、机器学习scikit-learn:该项目文档齐全、讲解清晰,功能齐备,使用方便,而且社区活跃PyBrain:Python的一个机器学习模块,它的目标是为机器学习任务提供灵活、易应、强大的机器学习算法。PyBrain正如其名,包括神经网络、强化学习(及二者结合)、无监督学习、进化算法。因为目前的许多问题需要处理连续态和行为空间,必须使用函数逼近(如神经网络)以应对高维数据。以神经网络为核心,所有的训练方法都以神经网络为一个实例Orange:机器学习只是其的功能之一,主要还是侧重数据挖掘,可以用可视化语言或Python进行操作,拥有机器学习组件,还具有生物信息学以及文本挖掘的插件Shogun:文档齐全,开发活跃,更新快,运算速度也很快。主攻大尺度的核函数,尤其是大尺度核函数下的SVM。具有很多SVM的高级用法,比如多核配用等6、深度学习Theanopylearn2kerasnolearn + lasagnaCaffeExpresso:基于Python之Caffe的深度学习图形化设计/训练/浏览框架Minerva:拥有python编程接口。多GPU几乎达到线性加速。在4块GPU上能在4天内将GoogLeNet训练到68.7%的top-1以及89.0%的top-5准确率。和同为dmlc项目的cxxnet相比,采用动态数据流引擎,提供更多灵活性。
尽管Neo4j提供图形化的web操作界面既直观又简单,但对于coder而言,有很多方面是web给不了的,比如从执行时间上看优化效果,以及多句执行等。所以,更高级的Neo4j开发者还是需要在Shell中工作。 在本博文中,将介绍Windows下Cyhper Shell的基本用法。一、找到Cypher Shell 首先,找到安装目录,我的笔记本是win 10系统,下载的是64位的Neo4j版本,所以默认安装到了"Program Files"下的"Neo4J CE 3.1.4"文件夹下: 然后,在可执行命令文件夹bin中可以看到cypher-shell.bat,这个就是开启Windows下Cypher Shell大门的钥匙。 接下来,将该路径复制(C:\Program Files\Neo4j CE 3.1.4\bin):二、进入Cypher Shell 然后 ,使用"win+r"快捷键组合打开命令框,输入"cmd"回车进入Windows Shell: 接下来,输入命令"cd C:\Program Files\Neo4j CE 3.1.4\bin",进入bin目录,然后运行cypher-shell.bat批处理文件,便可进入Cypher Shell。 别忘了输入用户名和密码,输入正确登入数据库:三、使用Cypher Shell 现在,可以尽情地使用Neo4j了,比如查看当前节点: 别忘了,每条语句结束时要使用一个";"。对了,一定要顺便查一下帮助文档,了解shell的其他基本命令:四、退出Cypher Shell 很简单,输入":exit"命令即可。 五岳之巅2017年5月28日(孟菲斯时间)10:50终稿于UM, FIT
首先,还是老样子,清楚当前数据库中所有的内容,干干净净开始学习新的一章。 match (n)-[r]-(n1) delete r,n,n1 match (n) delete n 接下来,还要使用第二篇博文中的人物和联系: CREATE (bradley:MALE:TEACHER {name:'Bradley', surname:'Green',age:24, country:'US'}) CREATE (matthew:MALE:STUDENT {name:'Matthew', surname:'Cooper',age:36, country:'US'}) CREATE (lisa:FEMALE {name:'Lisa', surname:'Adams', age:15,country:'Canada'}) CREATE (john:MALE {name:'John', surname:'Goodman', age:24,country:'Mexico'}) CREATE (annie:FEMALE {name:'Annie', surname:'Behr', age:25,country:'Canada'}) CREATE (ripley:MALE {name:'Ripley', surname:'Aniston',country:'US'}) MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley, matthew CREATE (bradley)-[:FRIEND]->(matthew) , (bradley)-[:TEACHES]->(matthew); MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley,matthew CREATE (matthew)-[:FRIEND]->(bradley); MATCH (bradley:MALE{name:"Bradley"}),(lisa:FEMALE{name:"Lisa"})WITH bradley,lisa CREATE (bradley)-[:FRIEND]->(lisa); MATCH (lisa:FEMALE{name:"Lisa"}),(john:MALE{name:"John"})WITH lisa,john CREATE (lisa)-[:FRIEND]->(john); MATCH (annie:FEMALE{name:"Annie"}),(ripley:MALE{name:"Ripley"})WITH annie,ripley CREATE (annie)-[:FRIEND]->(ripley); MATCH (ripley:MALE{name:"Ripley"}),(lisa:FEMALE{name:"Lisa"})WITH ripley,lisa CREATE (ripley)-[:FRIEND]->(lisa); 一、索引 Neo4j2.0版本在标签的基础上引入了索引,可以对标签进行限制和索引。这种方式即有助于数据完整性检查,也有利于优化Cypher。上一篇博文最后介绍了限制,本篇关注度的则是索引的用法和功能。 Neo4j的索引和其他RDBMS的定义相类似,主要用于提升节点找寻的性能。对于任何已有数据结构的更改操作,索引自动更新。如果出了错而导致索引处于无效状态,便需要差错并重新生成它们。 Cypher查询会自动使用索引,Cypher有一个查询计划器和查询优化器,可以对查询进行评估并尝试尽全力依据选索引择最短执行时间。 创建索引的过程并不复杂: 首先,使用如下语句对标签MALE和属性name创建一个索引: create index on :MALE(name) 核实是否已经创建,书上说需要在neo4j-shell中使用下列命令:schema ls。但我在Web界面上使用则是报错,没有此命令。 删除索引使用如下命令: drop index on :MALE(name) 一旦索引建立,随后但凡在where从句中出现具有索引的属性时,不论是简单的等值比较还是其他条件,索引的使用都是自动的。然而,还有一种外显的指定索引的使用方式,就是using从句。如: create index on :MALE(name) match (n:MALE) using index n:MALE(name) where n.name = "Matthew" return n 结果如下图所示,很遗憾在非终端中看不到查询的耗时,尽管目前的学习和测试是在Win 10下完成的,但也可以使用windows准备的Cypher-shell,可以参考另一篇文章《Neo4j入门点滴(五):Windows Shell for Cypher》。 重点来了,必须记住:我们也可以在一个单一查询中使用using从句并提供多个索引项来给Cypher Query Optimizer提供索引提示,也可以使用scan给Cypher Query Planner先扫描所有标签然后再执行后续的过滤,这种做法的结果意味着优秀的性能,毕竟使用标签本身可以不必考虑那些不必要的数据。如: match (n:MALE) using scan n:MALE where n.name = "Matthew" return n 尽管上述查询的结果是一样的,但性能会更好。需要注意的一点,使用scan时使用的是:MALE,而非index时的:MALE(name),这点一定要警惕。二、Index Sampling 真不太好翻译,所以还是直接使用英文词组吧。 其实,所有Cypher查询执行的第一步就是先要制订出一个有效的执行计划。尽管这个计划由Neo4j自行创建,但创建之前系统需要知道当前数据库、索引、索引所含的节点数、联系等多种重要信息。这些信息将帮助Neo4j设计一个效率高、效果好的执行计划,从而使得我们的查询请求被更快地响应。下一小节在详细讨论执行计划的过程,但是有效执行计划其中一个步骤就是Index Sampling。实际上,Index Sampling就是我们经常对索引进行分析和取样,确保索引统计数据更新,以及在数据库增删改数据的并对相应索引进行更改的全部过程。 我们可以通过开启Neo4j数据库的下列属性实现自动index sampling(Linux下是文件neo4j.properties,windows的还没找到): index_background_sampling_enabled:该布尔属性值默认被设置为False,将其改为True开启自动sampling。 index_sampling_update_percentage:定义了在触发sampling之前需要被改变索引的百分比阈值。 当然,也可以在终端中输入如下命令手动开启: schema sample -a:触发对所有索引做sampling。 schema sample -l MALE -p name:仅仅触发标签(l)和属性(p)定义的索引的sampling。 三、理解执行计划 对于所有查询的执行计划的生成,Neo4j使用的都是基于成本的优化器(Cost Based Optimizer,CBO),用于制订精确的执行过程。可以采用如下两种不同的方式了解其内部的工作机制: EXPLAIN:是解释机制,加入该关键字的Cypher语句可以预览执行的过程但并不实际执行,所以也不会产生任何结果。 PROFILE:则是画像机制,查询中使用该关键字,不仅能够看到执行计划的详细内容,也可以看到查询的执行结果。 举例如下: profile match (n) where n.name = 'Annie' return n 如下图所示: 点击展开后,是这样: 此外,我还发现,Shell模式下,explain和profile都不如Web界面输入的信息多,不知道是不是版本的问题,还是参数设置的问题:四、分析并优化查询 还是用刚才Annie那个例子,正如所见,原查询并不高效,因为AllNodesScan需要对所有节点逐一进行匹配。然而,别忘了,Cypher引入的标签系统可不是摆着看的,试着对刚才的例子添加标签: profile match (n:FEMALE) where n.name = 'Annie' return n 结果如下图: 可以看到,优化器由AllNodesScan变为了NodeByLabelScan,过滤的过程也有原来的6-1-1缩减为当前的2-1-1。但这并没有结束,还可以进一步优化,对,就是使用index。 create index on :FEMALE(name) 其他都不变,只是提前创建一条索引,这下子优化器就可以用NodeIndexSeek,整个过程由刚才的2-1-1变成了现在的1-1-1,也就是没有任何不必要的额外付出,一击命中! 具体的优化参数,可以参考estimated rows和db hits这两个数值,都是越小越好。前者指需要被扫描行数的预估值,后者是系统实际运行结果的命中(I/O)绩效。其实,并不存在放之四海而皆准的通用标准(否则开发者已经就直接把这些标准内化到Neo4j中了),所以还需要积累经验,经常对Cypher的执行进行分析和优化。 五岳之巅 2017年5月29日(孟菲斯时间)09:10终稿于Dorsy Ave, Memphis, TN
在上一篇博文中,重点介绍的是Neo4j的读操作,在本文中则将聚焦于Neo4j的写操作,主要包括:创建节点和联系、转移节点和联系以及Cypher查询优化三大问题。一、创建节点和联系 节点和联系是构成Neo4j图数据库的主要元素,熟悉和掌握基本的节点和联系创建操作非常重要。(一)操作节点 Node乃Neo4j数据库中最核心的元素,其他元素或者连接于此或者对其进行补充定义或描述。首先,使用下列命令删除当前数据库中的全部已有内容,然后从无到有,一点一滴地学习: match (n)-[r]-(n1) delete n,r,n1; match (n) delete n; 好了,现在正式开始。(1)单节点 可以使用create (n);或者create ();或者 create (n) return n;三种方式中的任意一种来创建一个节点。如果仅仅是为了创建一个节点而没有对该节点更进一步的操作,那么就可以省略自定义变量n而使用空括号()。同样,如果不需要返回结果,那么连return从句也是不必要的。 重要的是,Neo4j为每一个节点都分配了一个唯一的ID用作标识。然而,这些ID实际上是Neo4j内部的,而且可以随Neo4j安装或版本的不同而变化,因此强烈建议不要在构建用户定义逻辑中使用节点ID,通俗而言就是用户的代码实现尽量不要使用ID。但是,话又说回来了,并不是根本不能用,比如: match (n) return ID(n) 不过,和其他属性不同,没有n.id或n.ID的用法,只能使用id()该函数来提取ID。如:(2)多节点 多节点的创建,就是多个元素的并列,如:create (n), (n1)或者create (), ()等。那么,有意思的是,如果create (n), (n)连续两个相同的n,会发生什么样的结果呢?答:结果会报错,系统提示因为已经创建了第一个节点n了,不能重复创建。如图所示:(3)带标签的节点 Neo4j使用标签实现对相似节点的分组和分类,而且标签还可以用来创建索引(index)从而有助于优化对节点的查询。创建有标签的节点,就是将冒号开始的标签写入即可。学以致用,一口气新建两个带标签而且是多标签的Nodes: create (n:MAEL:BOY:STUDENT), (n1:FEMAEL:TEACHER) return n, n1 多说一句,和C语言的命名规则一样:“数字字母下划线,首字母不能为数字”,在Neo4j中同样起作用。输入:123这样的标签会报错,而输入:a123或者_123则不会。(4)带属性的节点 正如本系列入门点滴的第一篇博文所言,使用属性的实现方式是键值对(key-value pairs),如: create (n:MALE{name:"haha", age:20}) return n 更进一步,属性值既可以是某一个值,也可以是一个数组。虽然NULL并不是一个合法的属性值,但却可以在未定义key的情况下被处理。先了解一下Neo4j属性的数据类型吧,很丰富: 那么,试试创建一个带有字符串数组的属性: 然后,我又创建了一个:create (x:MALE{city_beento:['北京', '孟菲斯']}) return x。这下有意思了,试着搜索一下: 结果是这样: match (n{city_beento:['北京']}) return n, 命中零个 match (n{city_beento:['北京','孟菲斯']}) return n, 命中一个 match (n{city_beento:['北京','孟菲斯','芝加哥']}) return n, 命中一个 match (n{city_beento:['北京',*]}) return n, 语句报错 match (n{city_beento:[]}) return n, 命中零个 所以,方括号中的属性值实际上是作为一个整体出现的,直接匹配属性只能精确命中。当然,如果需要模糊匹配,那么就可以在where从句中使用in来灵活实现: match (n) where '北京' in n.city_beento return n (二)操作联系 联系是Neo4j图中另一个核心的元素,对于任何节点或属性而言,只有与其他节点相连时方能体现其重要性。(1)单联系 单向联系使用有向箭头->或 create (n:MALE{name:'Kevin'})-[r:FATHER]->(n:MALE{name:'Leo'}) or create (n:MALE{name:'Kevin'})-[r:FATHER]->(n1:MALE{name:'Leo'}) return n,r,n1 实际上,上述例子是我从书中改的,但很遗憾,第一句是错误的,决不能再使用n,不论是否有return从句。第二句才是正确的。而且,我要说明一下,例子中的:FATHER其实是一个标签形式,但书上说这是联系的名字。但我比较发现,这就是标签,如下图所示:(2)多联系 多联系就是一口气多写点: create (n1)-[r1:friend]->(n2)-[r2:friend]->(n3),(n2)-[r3:friend]->(n4) return n1,r1,n2,r2,n3,r3,n4 结果如下图所示: (3)带有属性的联系 没什么特别的,只是在联系中添加属性而已,和节点一样,如下图:(三)具有节点和联系的全路径 也没什么特别的,全路径就是把create语句全部保存到一个变量中,上例可以重写为: create k = (n1)-[r1:friend{location:'China'}]->(n2) return k (四)创建唯一的节点和联系 刚才创建的节点和联系或多或少有些盲目,有可能引起和给定图中已存在的节点或其属性相重复。所幸Neo4j提供了create unique语句,这个语句放在match和create这里,对于match上的东东会新建缺省元素。这个语句使得我们可以没有重复地实现对给定进行原图最小程度的改变。 match (n) where id(n) = 52 create unique (n) return n,r,n1,n2 其实已经存在节点n了,这时候对n做了n3节点的扩充链接,n节点就不会重复创建,结果如图: 在这个例子中,我同时对n节点的属性也进行了更新,代码:create unique (n{name:'n1'})创建就是创建,更新已有的就需要另一个语句了:set!(五)Create Unique和Merge 尽管之前的博文已经提到了merge从句,但现如今还是要再来个quick recap。Merge语句出现在Match和Create的组合中,用于搜寻目标节点、属性、标签或联系。如果目标已经存在,那么直接PASS,否则就直接创建目标对象。与Create Unique类似,Match+Merge+Create也避免出现元素重复,然而二者并不是一样的,差别就在于:Create Unique部分匹配就可以,而Merge则只有整个pattern都匹配才创建,否则什么也不做。 Merge语句实际上后跟on match和on create两个子句,pattern匹配则走on match,不匹配则走on create分支。与Create Unique不同,Merge能够创建索引和标签,甚至被用于创建单节点。上例子,先创建三个节点及其联系: create (f1:FEMALE{name:"Sheena"}),(m:MALE{name:"Oliver"}),(f2:FEMALE{name:"Sally"}),(f1)-[r:FRIEND]->(m)-[r1:FRIEND]->(f2) return f1,r,m,r1,f2 结果如图所示: 接下来,使用Merge匹配已存在的元素并新建其他元素: match (f1:FEMALE{name:"Sheena"}),(m:MALE{name:"Oliver"}),(f2:FEMALE{name:"Sally"}) merge (f1)-[r:FRIEND]->(m)-[r1:FRIEND]->(f2)-[r2:FRIEND]->(f1) return f1,r,m,r1,f2,r2 结果很震撼,并没有去重,而是将联系全部重建一遍: 看来,merge本身并不能直接避免重复,起码在当前这个版本下!使用的时候一定要注意。(六)使用限定条件 Neo4j在version2后引入了对标签进行限定的概念。截止目前为止,Unique限定能用,但将来会有更多的。 通过如下方式可以对MALE标签生成一个Unique限定: create constraint on (n:MALE) assert n.name is unique 由此,可以确保name属性是唯一的,比如再创建一个相同名字的节点与之相连: match (n:MALE{name:'Oliver'}) create (n1:MALE{name:'Oliver'})-[r:FREIND]->(n) return n1,r,n 便会提示,不能新建因为有标签MALE的一个节点其姓名已经是Oliver了,如图: 这个安全功能,很实用!若想删除之前加上的限定条件,则需要使用drop: drop constraint on (n:MALE) assert n.name is unique Constraint也可以配合Merge使用,如果发现节点已存在,直接返回而不会重复创建。但是我测试了一下,并没有发现被拒,这个Merge问题仍然有待于后续再次深入探索。二、修改节点和联系 主要讨论如何更新标签、属性和联系。(一)更改节点属性 具体方式就是借助Match匹配节点,然后通过Set更改值。如: match (n:FEMALE {name:"Sheena"}) set n.surname = "Foster" return f 增加和修改可以使用上述方法,但删除属性就不止一种方法了,一共两种,一是使用set将对应属性设置为NULL,二是使用remove,如下: match (n{name:'Sheena'}) set n.middlename = NULL return n The other way is: match (n{name:'Sheena'}) remove n.surname return n (二)更改标签 和之前更改属性相似,也是使用set和remove进行操作,但是不同的是没有set :XXX = NULL的写法。看例子就好: match (n{name:'Sheena'}) set n:GOODMAN:BADMAN return n 如下图,当然写几个标签都可以: 然后把BADMAN标签去掉,然后再加入一个新的标签: match (n{name:'Sheena'}) remove n:BADMAN set n:GOODGOODMAN return n 最后需要说明一点:对于用相同名字替换已有标签的操作不会有任何实质性的操作发生。(三)更改联系 与属性和标签不同,并没有更改联系的语法词。唯一的方法就是首先移除这些联系,然后创建新联系。比如:如果Sheena和Oliver不再是朋友关系,那么匹配二者的联系并且删除这个联系即可。 match (n{name:'Sheena'})-[r:FRIEND]-(n1{name:"Oliver"}) delete r return n,n1 结果如下图所示: 五岳之巅 2017年5月25日(孟菲斯时间) 18:05 终稿于Dorsey
Announcement: All data comes from the book "Building Web Applications with Python and Neo4j", just for study & not for commerce. 模式及模式匹配(Pattern and Pattern matching)此乃Cypher的核心,描述了我们想要查找、创建或更新的数据的形状。不理解模式和模式匹配,就写不出既有效果又有效率的查询。一、数据准备 首先,输入如下命令清空当前数据库: match (n)-[r]-(n1) delete n,r,n1; match (n) delete n 第一条命令删除相互联系的所有节点及其联系,第二句则删除所有独立的节点。 然后,创建一堆男人和女人: CREATE (bradley:MALE:TEACHER {name:'Bradley', surname:'Green',age:24, country:'US'}) CREATE (matthew:MALE:STUDENT {name:'Matthew', surname:'Cooper',age:36, country:'US'}) CREATE (lisa:FEMALE {name:'Lisa', surname:'Adams', age:15,country:'Canada'}) CREATE (john:MALE {name:'John', surname:'Goodman', age:24,country:'Mexico'}) CREATE (annie:FEMALE {name:'Annie', surname:'Behr', age:25,country:'Canada'}) CREATE (ripley:MALE {name:'Ripley', surname:'Aniston',country:'US'}) 此时有节点但没有联系,结果如下图: 然后我一堆输入下列联系语句,总报错。但逐条输入就没问题了: MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley, matthew CREATE (bradley)-[:FRIEND]->(matthew) , (bradley)-[:TEACHES]->(matthew); MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley,matthew CREATE (matthew)-[:FRIEND]->(bradley); MATCH (bradley:MALE{name:"Bradley"}),(lisa:FEMALE{name:"Lisa"})WITH bradley,lisa CREATE (bradley)-[:FRIEND]->(lisa); MATCH (lisa:FEMALE{name:"Lisa"}),(john:MALE{name:"John"})WITH lisa,john CREATE (lisa)-[:FRIEND]->(john); MATCH (annie:FEMALE{name:"Annie"}),(ripley:MALE{name:"Ripley"})WITH annie,ripley CREATE (annie)-[:FRIEND]->(ripley); MATCH (ripley:MALE{name:"Ripley"}),(lisa:FEMALE{name:"Lisa"})WITH ripley,lisa CREATE (ripley)-[:FRIEND]->(lisa); 现在可以看到基本数据集合的样貌: 二、模式简介(1)Pattern for Nodes 匹配节点是最基本也是最简单的一种,使用括号进行描述。但是要注意,如果不额外使用属性或标签,那么括号可以省略: MATCH (a) return a 等价于: MATCH a return a; 结果有四个节点都是男性,如图: (2)Pattern for Labels 就是增加“:标签”进行限定,需要说明的是,可以同时使用多标签,起到交集的作用,如下第二句就使用了多标签: MATCH (n:MALE) return n; MATCH (n:MALE:TEACHER) return n; 结果返回的只有一个节点: (3)Pattern for Relationships 联系就是两个给定节点之间的连接,既可以是单向的,也可以是双向的,由[]和命名组成。 看一个单向的例子: match (a:TEACHER)-[b:TEACHES]->(c:STUDENT) return a,b,c 在这个例子中,系统首先搜寻TEACHER和STUDENT标签的节点,然后在这些节点中再找寻符合TEACHES联系的。 双向就是不需要箭头标识了,如下: match (a:MALE)-[b:FRIEND]-(c:FEMALE) return a,b,c (4)Pattern for property 属性的匹配使用的是花括号和键值对,其间使用都好分隔,如下: match (a:MALE{ name:"John", age:24} return a 三、使用Where从句(1)Where 如果仅仅使用Pattern并不能充分地满足要求,别懵逼,还有Where在。可以使用Where进一步过滤数据,但是要注意Where条件句本身并不能单独使用,只能用在match、optionalmatch、start或with的后面。比如: match (x) where x.age return x 此时,只有一个人符合要求:(2)Where从句中使用Pattern 对于一个集合而言,如果是空集,那么就代表false,非空则表示true。可以使用in这个关键词来进一步限定: match (x) where x.name in ["John", "Andrew"] and x.age is not NULL return x 当然,也可以使用not和正则表达式进行过滤: match (x) where x.name =~ "J.*" return x 在这种情况下,不是= ~"xxx",而是 =~ "xxx",也就是说=~这是一个符号,千万别写错了。 好了,以下要介绍一些此书上没有技巧: [1] 使用别名: with 'AGE' as haha match (x) where x[toLower(haha)] return x 注意,Neo4j中属性名是大小写敏感的,如果写成x.AGE,则系统会提示并没有该属性: 但是,“.”并不等同于“[]”,比如如下写法就是错误的: Why?我终于发现,并非“.”不等同于“[]”,而是二者确实相等,但用法有讲究。对于[]而言,其间必须是常量,所以当我把x[age]写成x['age']后,就顺利通过了,而且返回结果与x.age一样: [2] 使用exists()函数进行属性检验: match (x) where exists(x.age) return x.name 以前使用过has(),但现在被exists()代替而移除了。 [3] 字符匹配: 这绝对是一把利器,使用starts with、ends with或contains,匹配字符串以何种模式开始,以何种模式结束或者其中包含什么。非常便利!比如: match (x) where x.name starts with "B" return x.name 或者: match (x) where x.name contains "a" return x.name (3)其他从句 [1] order来排序(默认是升序,支持混排) [2] limit来限定返回数,skip则表示忽略最前面的。从而使用limit和skip的组配,可以取到中间的值: match (x) return x order by x.age skip 3 limit 2 返回的就是“不要前3个,只要第4和第5”。确实很灵活!(4)with从句 with也是非常有用的一种从句,在介绍with之前,需要先研究一下“,”。比如在如下语句中,逗号是作为并列出现的,结果返回x和y两个人的信息,包括return语句中的x,y之间的逗号也都是这种用法。 match (x{name:"John"}),(y{name:'Annie'}) return x,y 好的,继续,对于如下的初始情况: 执行以下的语句会有什么结果? match (x{name:'Lisa'}) return count(y) 我觉得应该是2,但我错了,结果是4。如下图: 为什么会是这样?也就意味着把两个间接的联系也算上了?好吧,自己再试试,这次用双向试试。结果大跌眼镜,依旧是4: match (x{name:'Lisa'})--(y)--() return count(y) 用Brandley的结果竟然是8,使用有方向的话是3。我又重新核对了一遍预设的所有联系,确实不应该是3。难道是BUG?(需要换个版本试试) OK,话说回来,让逗号出现在with中,书中的例子如下: match (x{name:'Bradley'})--(y)-->() with y, count(*) AS cnt where cnt > 1 return y 返回值是Matthew,这没问题。因为符合模式的所有记录中,只有Matthew超过两条联系。问题来了,必须写with y才能限定吗?如果我去掉y呢? match (x{name:'Bradley'})--(y)-->() with count(*) AS cnt where cnt > 1 return cnt cnt的值就变成了3,好的,我再加上y,看看cnt值: match (x{name:'Bradley'})--(y)-->() with y, count(*) AS cnt where cnt > 1 return cnt 这时,返回的cnt就成了2了。上述的尝试充分说明了with y, xxx这个模式中,逗号前的y起到限定的作用,如果不加y,那么: match (x{name:'Bradley'})--(y)-->() return count(*) 记录数就是3,表示命中的自Bradley发出的3条联系及其节点,如果推论正确,那么添加一个z表示目标节点,那么count(z)就应该是2个: match (x{name:'Bradley'})--(y)-->(z) return count(z) 结果是3个,但是如果我加上distinct,则变成了2个: match (x{name:'Bradley'})--(y)-->(z) return count(distinct z) 明白了,有些东东重复计算了,现在再试一下那些不解的例子: 也就是说,有向联系的结果加入distinct是正确的,没有问题,不加就是4和2。无向联系就见了鬼了: 更加奇怪的是,一下结果并不返回John: 天啊,神啊。我终于发现是怎么回事了,都是我的错!怪我并没有理解的很深。 细细讲一下,我一直把(x)--(y)--()当成了一组联系,实际上这是错误的,因为联系并不是用()表示,而是用[]表示。看看,不论有方向还是没有方向,这下全对了: 好吧,现在主要来看()--()--()三个括号的连用。那么我先试试-而不是--,如: 很显然,结果是错误的。也就是说match (x{name:'Lisa'})-(y)-(z),这种写法就是不对的。当然,换成--就没有语法错误了:match (x{name:'Lisa'})--(y)--(z) return count(*),但结果是4。现在我明白,因为(a)--(b)--(c)表示节点之间的连接关系,就是说要满足a是Lisa,而且b和a是连接的,并且c还要和b相连。通俗地讲,就是以a为中心,向外扩2层。如果我理解的是对的,那么match (x{name:'Lisa'})--(y)--(z) return z,结果就应该是最外层的两个节点了。而且match (x{name:'Lisa'})--(y) return count(*),就应该与Lisa直接相连的3个节点罗。试试,检验一下: 恭喜自己,虽然费了番周折,但终于搞定!反过来说,对于联系也可以这么玩:[a]-(b)-[c],我没试,但我相信是可以的。Cypher真的很灵活! 接来下,使用with x增加限定条件,进行创建。但我发现不论有没有这个with x,都是一样的,创建了三个kai:(5)union和union all从句 union的用法与SQL一样,用于连接两个Match,返回结果中剔除了重复记录。但union all功能一样,但不剔除重复记录。 match (x:MALE)-[:FRIEND]->() return x.name, labels(x) union match (x:FEMALE)-[:FRIEND]->() return x.name, labels(x) labels()返回的是全部的标签,有几个返回几个,如下图所示: 但是,要注意:没有label()这个返回一个标签的函数。 这一篇博文更长,终于告一段落了。接下来会开启第三篇。 五岳之巅 2017年5月23日(孟菲斯时间) 20:37 终稿于Dorsey
Cypher,读作(赛佛儿)。名词意为:零,零的记号,或密码索引书;动词含义为计算或用密码书写。不过,更准确的引申要从街舞中借鉴,在街舞中,Cypher就是围圈跳舞,不分先后,没有对手,就是一次一次即兴的到中间去跳。在社会网络分析(SNA)中,Neo4j的核心实现形式语言就是功能类似这种围圈舞蹈的Cypher。 Cypher我理解是一种联系操作语言,之所以将其称为“联系”就是要使之和传统SQL数据库的“关系”相区分。操作对象即图数据库独有的节点(Nodes)、标签(Labels)、联系(Relationships)和属性(Properties)。解释一下,以便理解的更为深入: Node:表征实体,如:人、公司、账户或其他类似的东西。 Label:标签不是一开始就有的,后续更新的版本加入了这个功能,极为好用。因为人脑的两种基本认知方式之一就是分类,而标签就是最佳的方法。标签用于标识Node的类别,一个节点可拥有一个或多个标签。标签有助于创建索引,加速检索。 Relationship:联系定义了两个Node之间的连接。联系还可以有自己的属性和方向。 Property:用于存储Node的相关信息,是Node的内涵定义。属性可以被Node和Relationship拥有,一如Node一样,Property也是一种广泛而基本的存在。 为了更深入地理解Cypher的语法,需要提前说明一下Cypher查询的执行过程: 首先,进行语法解析、正确性检查、产生执行计划; 其次,定位至初始节点; 再次,选择和遍历联系; 最后,更改或返回值。 后续语法的执行基本上都是这四个步骤的不断重复。 一、基本语法(CURD): 1. Create 试着创建一个Node,这个节点是一个人--顾双双,是我心理咨询的一个来访者,性别女,年龄23。仿照基本格式先写一个: create (顾双双:患者{gender:"女",age:"23"}) 请注意在下图的结果中,标签是“患者”,节点当前显示的名字是第一个标签的内容“女”: 当然了,这和我的本意并不相符,我是打算创建姓名为“顾双双”的患者,希望姓名可以在Node中心显示出来。所以,现在CREATE的格式是:create (?:标签名{属性名1:"属性1值",属性名2:"属性2值"}),所以现在主要的问题是弄清楚“?”代表什么,或者这个部分是否可以省略。 弄清楚了:?代表的是创建的本实例,正规的一个格式是: create (n:患者{gender:"女",age:23}) 注意两点,第一是n,第二是23旁边没有括号了,也就意味着该值不是字符型而是数值型。n实际上是可有可无的,用于捕获create的结果,可以有也可以没有。故而,“n:患者”也可以写成“:患者”,结果是一样的。 好了,另一个与Create齐名的语法也必须介绍了,这就是:merge,非常非常重要。Merge好似if-else语句,基本逻辑是先检测merge后面的条件,看看有没有匹配的返回值,如果有则执行on merge分支,如果没有则走on create。逻辑很简单,humane:看是否需要merge,找到的话就合并,没找到就新建。 首先,merge条件部分可以单独执行,不过意义不大: 还是用例子说明: merge (x:患者{gender:"男"}) on match set x.name = "小明", x.birthday = 2007/06/02 on create set x.created_time = timestamp() 结果如图,虽然执行成功: 但年龄还是有问题: 到stackOverFlow上找了一下,都说需要手工将时间转成timestamp,因为Neo4j只有一个timestamp()函数而且还没有参数,很多人在抱怨这个问题,估计官方日后一定会增强这方面的功能。 执行了如下语句后,激活了On create分支,因为数据库中目前并没有 性别是“P”的患者: merge (x:患者{gender:"P"}) on match set x.name = "小明", x.birthday = "2007/06/02" on create set x.created_time = timestamp() 结果如图: 2. Update 更新的操作实际上是由set命令完成的,首先要定位到待修改的节点或联系,然后进行修改。举个例子: match (x:患者) where x.gender="男" set x.age=100 return x 这个例子说明不仅可以使用set更改值,还可以更改值类型,比如从string改为integer。3. Retrieve 实际上,查询或检索这一操作是Cypher实际应用中使用次数最频繁的,类似SQL数据库中的SELECT。在Neo4j中,主要是由Match及其后续限定的Where从句构成。 比如,通过如下语句新增一个节点,现在数据库中有一男一女两个节点: create (:患者{gender:"男",age:"23"}) 输入如下语句,返回标签为“患者”的所有节点(当前是两个): match(x:患者) return x 输入如下语句,返回标签为“患者”并且性别为“女”的所有节点(当前是一个): match (x:患者) where x.gender="女" return x Where从句的语法和SQL非常相似,比如is not null或者=,之间还可以使用and、or等逻辑运算符进行组合。并且,除了Create和Delete语句,其他所有语句都应该以return结尾,否则报错。 还有一个就是Optional Match,其他都一样,差别在于没找到Match不返回任何结果,而Optional Match返回NULL,如下图的“records”所示: 在Match查找前,可以进行定位以加快检索速度和效率。一般而言,Cypher语句以Start开始,每一条查询语句可以有多个起始点(starting points),借助start可以制定Legacy index,虽然这个东东现在已经被schema取代了,但为了后向兼容还是保留了基本功能,如下例所示: start n = node:nodesIndx (Gender = "男") return n 然而,实际应用中,还有一个重要的检索功能必须掌握,那就是所谓的“Aggregation”。这种聚合实质上是grouping,就是对结果进行统计操作,小到count、max、min,大到stdev、stdevp,更不用说distinct了。比如将之前的例子的返回值加一个count: match (x:患者) where x.gender="女" return count(x) 结果是1,如下图所示: OK,another trick,使用distinct: match (x:患者) where x.age="23" return count(distinct x.gender) 结果如下,返回2,但如果是x.age则只是1啦: 查询部分先总结到这儿。4. Delete 删除任何东西都可以使用Delete,但将上述创建的所有内容一口气删除,不能使用: match (n) delete n 而应该使用: match (n) detach delete n 因为使用第一种方式,会报错:“Cannot delete node, because it still has relationships.”。究其原因,在于高版本的Neo4j加强了数据保护,对于有联系的节点,需要先删除联系再删除节点。然而,使用detach便开启了弱保护机制。 但是,还有个好用的东东叫remove,专门用来删除属性和标签,比delete安全一些。比如: match (x:患者{gender:"P"}) remove x.created_time return x 结果如下图,created_time属性就被删除了: 5. 总结 之前说Cypher的优化主要是读操作,原因就在于所有操作(Create、Set、Delete或Remove)第一步就是要执行match,而match就是读操作,对特定节点或联系的定位都依赖于读操作。所以,读操作在图数据库中使用的是如此广泛和普遍,以至于成为主要的优化对象一点也不为过。 已经写成长文了,这篇就先到此为止吧。 五岳之巅 2017年5月21日(孟菲斯时间) 11:57 终稿于UM, FIT
再起征 --返程前记 余晖未了, 阴星魅娆。 残阳溢血, 古月邪桥。 风涤沙脊, 枯枝诈俏。 十面黑漠,千古涸道。 将行进, 勒马回望, 尸气浮漂。 待归日, 浩气竞天, 荡平魔垇。 斩群妖,何时难? 莫待银发对垂憔! 2017年2月20日,FIT, Memphis 3月14日Publishing,5283 Dorsey Ave, TN, Memphis
这篇文章的题目取得很大,主要是适用面确实广。如果只是开发环境下,有限的数据量其实不足以考虑这个问题。然而,在生产环境下,数据量往往比较大,已经到了使用phpmyadmin导出sql文件大小为0的情况。 我最近在抓盗版书的数据,其中一个表就已经达到100M了,含有一百三十万条记录,虽然这并不算多(是抽样样本),但是phpmyadmin自行导出已然无效。这种情况怎么办呢?修改php和mysql的config配置文件固然可以,即使这次能够设置200M的配额,我也无法预料今后会不会有超过200M的情况。所以,这种方法对我不可取。 于是,使用另一种方法: 进入phpmyadmin文件夹,修改config配置文件,增加upload和download两个具体文件夹: 此时,在phpmyadmin操作面板中便可选择“保存到务器上的 download/ 文件夹中”这个选项了,导出后去download文件下就能看到目标文件。由于直接导入到服务器上,所以执行的速度非常快。 最后,再通过其他文件传输工具下载下来就OK,上传是下载的逆操作,原理一样,只是先把文件放到upload里而已。这种方式最省事,也最靠谱,当然不太适用于虚拟主机,我用的是独立主机服务器,所以Everything is under control。
今天在抓取淘宝网网页的时候,使用了: #店名 shopname = driver.find_element_by_xpath(".//*[@id='page']/div[2]/div/div[2]/ul/li[1]/a/span").text.strip() #掌柜名 dealername = driver.find_element_by_xpath("./html/head/title").text.strip() dealername = dealername[dealername.find('-')+1:dealername.rfind('-')] 对于xpath,当然好用,毕竟Firefox和Chrome可以自动生成,所以爬虫开发的速度会更快。然而,得到的结果很惊讶,全部为空。我突然之间陷入了迷惑,不可能是因为版本的问题吧,毕竟selenium已经这么成熟了。下午试了很多次,都是无功而返,我非常沮丧。 晚上继续,首先要找到问题出在什么地方。使用page_source查看,发现网页代码一应俱全。难道是非得把鼠标移动到特定位置,弹出菜单激活Js?于是使用: driver.get('https://shop594784981.taobao.com') time.sleep(3) menu = driver.find_element_by_xpath("//*[@id='header-content']/div[2]/p/span[1]/span[1]/a") ActionChains(driver).move_to_element(menu).perform() time.sleep(2) 弹出了隐含层,又如何呢,还是不行啊。~~~接着再尝试,试试其他 print(driver.find_element_by_id("J_TEnterShop").text) 使用ID就可以了。然后,我就非常仔细地观察了ID这块的HTML结构特点,发现确实和之前要抓的结构不一样。接着我又试了一下这个Id的xpath,顺利提取。看来不是text方法的问题,也不是xpath的问题。而是结构的问题,对于xpath能提取什么样的结构我之前是没有弄清楚,现在举例说明一下: span class="shop-name"> 店铺: a href="//shop124836129.taobao.com?spm=a1z10.1-c.0.0.XEwkxh" target="_blank" class="J_TGoldlog" data-goldlog-id="/tbwmdd.1.044" data-spm-anchor-id="a1z10.1-c.0.0">锦文图书批发i id="J_TEnterShop">进入店铺/i>/a> /span> 我只想提取店铺名称,但店铺名称在XXYY结构中,目标是XX,使用xpath提取的XX路径使用text提取的结果是空。但YY的xpath提取则是“进入店铺”,使用整个a链接的xpath是“锦文图书批发进入店铺”。所以xpath看来要使用标签封闭结构才行。 那么问题来了,怎么提取“锦文图书批发”呢? 有两种方法,一是换一个具有“锦文图书批发”的地方提取,二是使用XXYY - YY的方式。
1、不消说,第一步肯定是安装Python。从网上的资料来看,Python2.7是不错的选择,然而我现在用的是Miix 700,一款64位跑的不怎么快的平板电脑,而且不涉及生产环境,所以将就一下自己刚装的Python3.5。 2、进入如下网址:http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv,里面啥都有,对应找到了Python3.5的OpenCV,然后下载64位的whl文件,26.3M。 3、进入下载目录,然后使用pip进行安装,如下图。网上有专门提示说不能用管理员权限安装,但没说原因,我打算用管理员权限装,然后再试试看。 4、然后,安装Numpy和Matplotlib,虽然前者是必须的而后者不是必须的,但没有显示图像肯定不中。所以,都用pip装好。
开发环境:Win10+Python3.5+Selenium2.53.6+IE11,均为64 bit硬件环境:联想MIIX700语言环境:English(US) 浏览器:Firefox(46.0.1)、IE(11.0.10240.16431)、Chrome(53.0.2785.143),均为64 bit刚才测试了一下,代码如下: from selenium import webdriver from bs4 import BeautifulSoup driver = webdriver.Firefox() #driver = webdriver.Ie() #driver = webdriver.Chrome("C:\Program Files\Python\Python35\Scripts\chromedriver") driver.get("http://www.baidu.com/") print(driver.title) driver.quit() 结果是:[Finished in 8.9s](Firefox,建议使用)[Finished in 9.0s])(IE,也不错)[Finished in 9.8s](Chrome,启动快,长时间运行时内存处理做的不错,但退出后做了更长的工作才结束) Tips:小技巧,用pip查询已安装包的版本号时,使用show即可,如下: pip show selenium
开发环境:Win10+Python3.5+Selenium+IE11硬件环境:联想MIIX700语言环境:English(US)在做数据爬取得时候,发现IE Driver出现白屏,跟着提示:“This is the initial start page for the WebDriver server“几经寻找,解决了问题。问题源自IE高版本的自我保护功能,使Selenium的切入机制遇到安全阻碍。解决方案如下:1、点击Tools,或使用快捷键Alt+x2、在弹出的菜单中选择”Internet options“3、在弹出的选项卡中,选择第二项"Security"4、逐次点击全部的Zone(共4个),然后全部不勾选"Enable Protected Mode"5、回到IE,再次进入Tools菜单,Zoom必须设置为100%至此,OK。
别和我说selenium中的webdriver用driver.page_source,我就是不想把整篇HTML文档每次都全部提出来做Soup。因为,对下面这样左右结构的论坛而言,每次内容的改变对于整个HTML页面而言实在是一个很小的部分,如果我想把整个网站所有MOOC课程评论爬下来的话,将要做多少无用功! 然而,百度遍中文内容并无解答。于是翻出去Google了一把,发现世界上已有前辈对该问题进行了解答: 主要思路是使用get_attribute方法,提取innerHTML,如下: 经验证,一切OK:
我在阿里云上碰到了这个问题,不论是64位还是32位都不行,如下图所示: 阿里官方给出的方案是安装时不选择Pip,如下图: 但是,为什么会这样呢?我查阅了Python官方Bug,在这里有回答http://bugs.python.org/issue10002 意思就是安装有充启请求,但微软不让,所以就装不了。好窘。
由于Chrome速度快,因此很早便使用Chrome Driver淘汰了IE Driver和PhantomJS Driver。最近的抓取工作出现了一个令人头疼的事情,单开一个Driver做while 1循环,每隔5分钟扫描抓取目标对象。然而Chrome Driver总是会在4~5个小时僵死掉。我做了性能和时间的记录: Turn 1:硕博家园 2016-1-6 16:45:00 Mem 1.45GB 2016-1-6 17:06:45 Mem 1.43GB chrome 38,000k 2016-1-6 17:14:14 Turn 2:考研版块 2016-1-6 17:19:14 Mem 1.43GB chrome 53,780k 2016-1-6 17:28:17 Mem 1.32GB chrome 49,672k Turn 3:xxxx 2016-1-6 17:33:14 Mem 1.33GB chrome 56,000k 2016-1-6 17:35:30 Mem 1.33GB chrome 55,728k Turn 4:lunwentougao 2016-1-6 17:33:14 Mem 1.33GB chrome 56,000k 2016-1-6 17:28:17 Mem 1.32GB chrome 49,672k ------------------------------------------ 2016-01-11 13:26:56 2016-01-11 17:20:42 22:23:30 02:22:28 2016-01-12 06:50:12 2016-01-12 11:30:37 2016-01-12 13:13:28 2016-01-12 18:05:44 所以,我打算重新换个Driver试试,到官网的Download页面下(www.seleniumhq.org/download/) ,能够看到现在陆续出现了更多浏览器的Drvier,包括opera、Edge等。 我下载的是Firefox。当然必须首先在服务器上安装好完整的Firefox浏览器。然后可以在Python中简单调用。capabilities我还不太会用,所以注销了: from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities #driver = webdriver.Chrome('C:\Python27\Scripts\chromedriver') #firefox_capabilities = DesiredCapabilities.FIREFOX #firefox_capabilities['marionette'] = True #firefox_capabilities['binary'] = u'C:\Python27\Scripts' #driver = webdriver.Firefox(capabilities=firefox_capabilities) driver = webdriver.Firefox() 经过一晚的测试,发现效果不错,没有什么问题,机器一直在正确的轨道上运行着: Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. >>> ================== RESTART: C:\datascrawl\ccnu_hf\ccnuHf.py ================== 2016-01-12 19:27:25 2016-01-12 19:27:45 2016-01-12 19:28:47 2016-01-12 19:29:47 2016-01-12 19:30:09 2016-01-12 19:30:31 2016-01-12 19:30:53 2016-01-12 19:31:15 Again_______________________: 2016-01-12 19:36:15 2016-01-12 19:36:37 2016-01-12 19:36:57 2016-01-12 19:37:38 2016-01-12 19:38:00 2016-01-12 19:38:22 2016-01-12 19:38:44 2016-01-12 19:39:06 2016-01-12 19:39:26 Again_______________________: 2016-01-12 19:44:26 2016-01-12 19:44:48 2016-01-12 19:45:08 2016-01-12 19:45:30 2016-01-12 19:46:11 2016-01-12 19:46:33 2016-01-12 19:46:55 2016-01-12 19:47:17 2016-01-12 19:47:39 Again_______________________: 2016-01-12 19:52:39 2016-01-12 19:53:20 2016-01-12 19:53:40 2016-01-12 19:54:02 2016-01-12 19:54:24 2016-01-12 19:54:46 2016-01-12 19:55:46 2016-01-12 19:56:08 2016-01-12 19:56:30 Again_______________________: 2016-01-12 20:01:30 2016-01-12 20:01:52 2016-01-12 20:02:12 2016-01-12 20:02:35 2016-01-12 20:02:57 2016-01-12 20:03:18 2016-01-12 20:03:59 2016-01-12 20:04:21 2016-01-12 20:04:43 Again_______________________: 2016-01-12 20:09:43 2016-01-12 20:10:25 2016-01-12 20:11:03 2016-01-12 20:11:24 2016-01-12 20:11:46 2016-01-12 20:12:08 2016-01-12 20:12:30 2016-01-12 20:12:52 2016-01-12 20:13:33 Again_______________________: 2016-01-12 20:18:33 2016-01-12 20:18:55 2016-01-12 20:19:32 2016-01-12 20:19:55 2016-01-12 20:20:17 2016-01-12 20:20:39 2016-01-12 20:21:13 2016-01-12 20:21:48 2016-01-12 20:22:23 Again_______________________: 2016-01-12 20:27:23 2016-01-12 20:28:17 2016-01-12 20:28:48 2016-01-12 20:29:23 2016-01-12 20:29:57 2016-01-12 20:30:32 2016-01-12 20:31:07 2016-01-12 20:32:01 2016-01-12 20:32:37 Again_______________________: 2016-01-12 20:37:37 2016-01-12 20:38:12 2016-01-12 20:38:32 2016-01-12 20:38:54 2016-01-12 20:39:16 2016-01-12 20:39:38 2016-01-12 20:40:00 2016-01-12 20:40:21 2016-01-12 20:40:43 Again_______________________: 2016-01-12 20:45:43 2016-01-12 20:46:06 2016-01-12 20:46:26 2016-01-12 20:46:48 2016-01-12 20:47:10 2016-01-12 20:47:32 2016-01-12 20:47:53 2016-01-12 20:48:15 2016-01-12 20:48:38 Again_______________________: 2016-01-12 20:53:38 2016-01-12 20:53:59 2016-01-12 20:54:20 2016-01-12 20:54:42 2016-01-12 20:55:03 2016-01-12 20:55:25 2016-01-12 20:55:47 2016-01-12 20:56:09 2016-01-12 20:56:31 Again_______________________: 2016-01-12 21:01:31 2016-01-12 21:01:53 2016-01-12 21:02:31 2016-01-12 21:02:53 2016-01-12 21:03:15 2016-01-12 21:03:37 2016-01-12 21:03:59 2016-01-12 21:04:21 2016-01-12 21:04:46 Again_______________________: 2016-01-12 21:09:46 2016-01-12 21:10:08 2016-01-12 21:10:28 2016-01-12 21:11:09 2016-01-12 21:11:31 2016-01-12 21:12:12 2016-01-12 21:12:34 2016-01-12 21:12:56 2016-01-12 21:13:18 Again_______________________: 2016-01-12 21:18:18 2016-01-12 21:18:40 2016-01-12 21:19:00 2016-01-12 21:19:41 2016-01-12 21:20:03 2016-01-12 21:20:45 2016-01-12 21:21:07 2016-01-12 21:21:29 2016-01-12 21:21:51 Again_______________________: 2016-01-12 21:26:51 2016-01-12 21:27:32 2016-01-12 21:27:52 2016-01-12 21:28:14 2016-01-12 21:28:36 2016-01-12 21:28:58 2016-01-12 21:29:20 2016-01-12 21:29:42 2016-01-12 21:30:04 Again_______________________: 2016-01-12 21:35:04 2016-01-12 21:35:44 2016-01-12 21:36:05 2016-01-12 21:36:45 2016-01-12 21:37:07 2016-01-12 21:37:29 2016-01-12 21:37:51 2016-01-12 21:38:13 2016-01-12 21:38:35 Again_______________________: 2016-01-12 21:43:35 2016-01-12 21:43:57 2016-01-12 21:44:17 2016-01-12 21:44:39 2016-01-12 21:45:01 2016-01-12 21:45:23 2016-01-12 21:46:03 2016-01-12 21:46:25 2016-01-12 21:46:47 Again_______________________: 2016-01-12 21:51:47 2016-01-12 21:52:09 2016-01-12 21:52:29 2016-01-12 21:52:51 2016-01-12 21:53:13 2016-01-12 21:53:34 2016-01-12 21:53:57 2016-01-12 21:54:19 2016-01-12 21:54:59 Again_______________________: 2016-01-12 21:59:59 2016-01-12 22:01:00 2016-01-12 22:01:37 2016-01-12 22:02:01 2016-01-12 22:02:23 2016-01-12 22:02:44 2016-01-12 22:03:26 2016-01-12 22:03:48 2016-01-12 22:04:10 Again_______________________: 2016-01-12 22:09:10 2016-01-12 22:09:32 2016-01-12 22:09:52 2016-01-12 22:10:14 2016-01-12 22:10:34 2016-01-12 22:10:55 2016-01-12 22:11:51 2016-01-12 22:12:13 2016-01-12 22:12:35 Again_______________________: 2016-01-12 22:17:35 2016-01-12 22:17:57 2016-01-12 22:18:18 2016-01-12 22:18:39 2016-01-12 22:19:01 2016-01-12 22:19:43 2016-01-12 22:20:05 2016-01-12 22:20:27 2016-01-12 22:20:48 Again_______________________: 2016-01-12 22:25:49 2016-01-12 22:26:11 2016-01-12 22:26:31 2016-01-12 22:27:12 2016-01-12 22:27:34 2016-01-12 22:27:55 2016-01-12 22:28:17 2016-01-12 22:28:39 2016-01-12 22:29:01 Again_______________________: 2016-01-12 22:34:01 2016-01-12 22:34:42 2016-01-12 22:35:03 2016-01-12 22:35:25 2016-01-12 22:35:46 2016-01-12 22:36:08 2016-01-12 22:36:49 2016-01-12 22:37:11 2016-01-12 22:37:33 Again_______________________: 2016-01-12 22:42:33 2016-01-12 22:43:15 2016-01-12 22:43:35 2016-01-12 22:43:57 2016-01-12 22:44:19 2016-01-12 22:44:41 2016-01-12 22:45:21 2016-01-12 22:45:43 2016-01-12 22:46:05 Again_______________________: 2016-01-12 22:51:05 2016-01-12 22:51:27 2016-01-12 22:51:48 2016-01-12 22:52:10 2016-01-12 22:52:31 2016-01-12 22:53:13 2016-01-12 22:53:54 2016-01-12 22:54:34 2016-01-12 22:54:56 Again_______________________: 2016-01-12 22:59:56 2016-01-12 23:00:18 2016-01-12 23:00:38 2016-01-12 23:01:00 2016-01-12 23:01:22 2016-01-12 23:01:44 2016-01-12 23:02:06 2016-01-12 23:02:28 2016-01-12 23:02:50 Again_______________________: 2016-01-12 23:07:50 2016-01-12 23:08:12 2016-01-12 23:08:49 2016-01-12 23:09:30 2016-01-12 23:09:51 2016-01-12 23:10:13 2016-01-12 23:10:35 2016-01-12 23:10:57 2016-01-12 23:11:19 Again_______________________: 2016-01-12 23:16:19 2016-01-12 23:17:00 2016-01-12 23:17:20 2016-01-12 23:17:42 2016-01-12 23:18:23 2016-01-12 23:19:05 2016-01-12 23:19:26 2016-01-12 23:19:48 2016-01-12 23:20:29 Again_______________________: 2016-01-12 23:25:29 2016-01-12 23:26:09 2016-01-12 23:26:30 2016-01-12 23:26:52 2016-01-12 23:28:54 2016-01-12 23:29:16 2016-01-12 23:29:57 2016-01-12 23:30:18 2016-01-12 23:30:40 Again_______________________: 2016-01-12 23:35:40 2016-01-12 23:36:02 2016-01-12 23:36:22 2016-01-12 23:36:44 2016-01-12 23:37:06 2016-01-12 23:37:47 2016-01-12 23:38:10 2016-01-12 23:38:31 2016-01-12 23:38:54 Again_______________________: 2016-01-12 23:43:54 2016-01-12 23:44:15 2016-01-12 23:44:36 2016-01-12 23:44:58 2016-01-12 23:45:20 2016-01-12 23:45:42 2016-01-12 23:46:03 2016-01-12 23:46:44 2016-01-12 23:47:06 Again_______________________: 2016-01-12 23:52:06 2016-01-12 23:52:28 2016-01-12 23:52:48 2016-01-12 23:53:09 2016-01-12 23:53:29 2016-01-12 23:53:50 2016-01-12 23:54:28 2016-01-12 23:54:50 2016-01-12 23:55:12 Again_______________________: 2016-01-13 00:00:12 2016-01-13 00:00:34 2016-01-13 00:00:54 2016-01-13 00:01:36 2016-01-13 00:01:57 2016-01-13 00:02:19 2016-01-13 00:02:41 2016-01-13 00:03:03 2016-01-13 00:03:25 Again_______________________: 2016-01-13 00:08:25 2016-01-13 00:08:47 2016-01-13 00:09:07 2016-01-13 00:09:29 2016-01-13 00:09:51 2016-01-13 00:10:13 2016-01-13 00:10:35 2016-01-13 00:10:57 2016-01-13 00:11:19 Again_______________________: 2016-01-13 00:16:19 2016-01-13 00:16:41 2016-01-13 00:17:01 2016-01-13 00:17:23 2016-01-13 00:17:45 2016-01-13 00:18:07 2016-01-13 00:18:47 2016-01-13 00:19:09 2016-01-13 00:19:32 Again_______________________: 2016-01-13 00:24:32 2016-01-13 00:25:33 2016-01-13 00:25:53 2016-01-13 00:26:15 2016-01-13 00:26:37 2016-01-13 00:26:59 2016-01-13 00:27:20 2016-01-13 00:27:43 2016-01-13 00:28:05 Again_______________________: 2016-01-13 00:33:05 2016-01-13 00:33:27 2016-01-13 00:33:48 2016-01-13 00:34:10 2016-01-13 00:34:32 2016-01-13 00:34:56 2016-01-13 00:35:18 2016-01-13 00:35:40 2016-01-13 00:36:02 Again_______________________: 2016-01-13 00:41:02 2016-01-13 00:41:24 2016-01-13 00:41:45 2016-01-13 00:42:25 2016-01-13 00:42:48 2016-01-13 00:43:09 2016-01-13 00:43:32 2016-01-13 00:44:12 2016-01-13 00:44:34 Again_______________________: 2016-01-13 00:49:34 2016-01-13 00:49:56 2016-01-13 00:50:16 2016-01-13 00:50:38 2016-01-13 00:51:00 2016-01-13 00:51:22 2016-01-13 00:51:44 2016-01-13 00:52:06 2016-01-13 00:52:27 Again_______________________: 2016-01-13 00:57:27 2016-01-13 00:57:50 2016-01-13 00:58:10 2016-01-13 00:58:32 2016-01-13 00:58:54 2016-01-13 00:59:16 2016-01-13 00:59:38 2016-01-13 00:59:59 2016-01-13 01:00:41 Again_______________________: 2016-01-13 01:05:41 2016-01-13 01:06:03 2016-01-13 01:06:24 2016-01-13 01:06:45 2016-01-13 01:07:07 2016-01-13 01:07:29 2016-01-13 01:07:51 2016-01-13 01:08:13 2016-01-13 01:08:35 Again_______________________: 2016-01-13 01:13:35 2016-01-13 01:13:57 2016-01-13 01:14:17 2016-01-13 01:14:39 2016-01-13 01:15:01 2016-01-13 01:15:23 2016-01-13 01:15:45 2016-01-13 01:16:06 2016-01-13 01:16:28 Again_______________________: 2016-01-13 01:21:28 2016-01-13 01:21:50 2016-01-13 01:22:10 2016-01-13 01:22:32 2016-01-13 01:22:54 2016-01-13 01:23:16 2016-01-13 01:23:38 2016-01-13 01:23:59 2016-01-13 01:24:21 Again_______________________: 2016-01-13 01:29:21 2016-01-13 01:29:43 2016-01-13 01:30:03 2016-01-13 01:30:25 2016-01-13 01:30:47 2016-01-13 01:31:09 2016-01-13 01:31:31 2016-01-13 01:31:52 2016-01-13 01:32:14 Again_______________________: 2016-01-13 01:37:14 2016-01-13 01:37:36 2016-01-13 01:37:57 2016-01-13 01:38:18 2016-01-13 01:38:40 2016-01-13 01:39:02 2016-01-13 01:39:24 2016-01-13 01:39:46 2016-01-13 01:40:07 Again_______________________: 2016-01-13 01:45:08 2016-01-13 01:45:29 2016-01-13 01:45:50 2016-01-13 01:46:12 2016-01-13 01:46:33 2016-01-13 01:46:55 2016-01-13 01:47:17 2016-01-13 01:47:39 2016-01-13 01:48:01 Again_______________________: 2016-01-13 01:53:01 2016-01-13 01:53:23 2016-01-13 01:53:43 2016-01-13 01:54:05 2016-01-13 01:54:27 2016-01-13 01:54:48 2016-01-13 01:55:10 2016-01-13 01:55:32 2016-01-13 01:55:53 Again_______________________: 2016-01-13 02:00:53 2016-01-13 02:01:15 2016-01-13 02:01:36 2016-01-13 02:01:58 2016-01-13 02:02:19 2016-01-13 02:02:41 2016-01-13 02:03:03 2016-01-13 02:03:25 2016-01-13 02:03:47 Again_______________________: 2016-01-13 02:08:47 2016-01-13 02:09:08 2016-01-13 02:09:29 2016-01-13 02:09:51 2016-01-13 02:10:12 2016-01-13 02:10:35 2016-01-13 02:11:16 2016-01-13 02:11:37 2016-01-13 02:11:59 Again_______________________: 2016-01-13 02:16:59 2016-01-13 02:17:21 2016-01-13 02:17:41 2016-01-13 02:18:03 2016-01-13 02:18:25 2016-01-13 02:18:47 2016-01-13 02:19:09 2016-01-13 02:19:30 2016-01-13 02:19:52 Again_______________________: 2016-01-13 02:24:52 2016-01-13 02:25:14 2016-01-13 02:25:34 2016-01-13 02:25:56 2016-01-13 02:26:18 2016-01-13 02:26:40 2016-01-13 02:27:02 2016-01-13 02:27:23 2016-01-13 02:27:45 Again_______________________: 2016-01-13 02:32:45 2016-01-13 02:33:07 2016-01-13 02:33:27 2016-01-13 02:33:49 2016-01-13 02:34:11 2016-01-13 02:34:33 2016-01-13 02:34:55 2016-01-13 02:35:16 2016-01-13 02:35:38 Again_______________________: 2016-01-13 02:40:38 2016-01-13 02:41:00 2016-01-13 02:41:21 2016-01-13 02:41:42 2016-01-13 02:42:04 2016-01-13 02:42:26 2016-01-13 02:42:47 2016-01-13 02:43:09 2016-01-13 02:43:31 Again_______________________: 2016-01-13 02:48:31 2016-01-13 02:48:53 2016-01-13 02:49:13 2016-01-13 02:49:35 2016-01-13 02:49:57 2016-01-13 02:50:18 2016-01-13 02:50:40 2016-01-13 02:51:02 2016-01-13 02:51:24 Again_______________________: 2016-01-13 02:56:24 2016-01-13 02:56:46 2016-01-13 02:57:06 2016-01-13 02:57:28 2016-01-13 02:57:50 2016-01-13 02:58:11 2016-01-13 02:58:33 2016-01-13 02:58:55 2016-01-13 02:59:17 Again_______________________: 2016-01-13 03:04:17 2016-01-13 03:04:38 2016-01-13 03:04:59 2016-01-13 03:05:21 2016-01-13 03:05:42 2016-01-13 03:06:23 2016-01-13 03:06:45 2016-01-13 03:07:07 2016-01-13 03:07:29 Again_______________________: 2016-01-13 03:12:29 2016-01-13 03:12:50 2016-01-13 03:13:11 2016-01-13 03:13:33 2016-01-13 03:13:54 2016-01-13 03:14:16 2016-01-13 03:14:38 2016-01-13 03:15:00 2016-01-13 03:15:22 Again_______________________: 2016-01-13 03:20:22 2016-01-13 03:20:43 2016-01-13 03:21:04 2016-01-13 03:21:25 2016-01-13 03:21:47 2016-01-13 03:22:09 2016-01-13 03:22:31 2016-01-13 03:22:53 2016-01-13 03:23:15 Again_______________________: 2016-01-13 03:28:15 2016-01-13 03:28:36 2016-01-13 03:28:57 2016-01-13 03:29:18 2016-01-13 03:29:40 2016-01-13 03:30:02 2016-01-13 03:30:24 2016-01-13 03:30:45 2016-01-13 03:31:07 Again_______________________: 2016-01-13 03:36:07 2016-01-13 03:36:29 2016-01-13 03:36:49 2016-01-13 03:37:11 2016-01-13 03:37:33 2016-01-13 03:37:54 2016-01-13 03:38:16 2016-01-13 03:38:38 2016-01-13 03:39:00 Again_______________________: 2016-01-13 03:44:00 2016-01-13 03:44:22 2016-01-13 03:44:42 2016-01-13 03:45:04 2016-01-13 03:45:26 2016-01-13 03:45:47 2016-01-13 03:46:09 2016-01-13 03:46:31 2016-01-13 03:46:53 Again_______________________: 2016-01-13 03:51:53 2016-01-13 03:52:15 2016-01-13 03:52:35 2016-01-13 03:52:57 2016-01-13 03:53:19 2016-01-13 03:53:41 2016-01-13 03:54:01 2016-01-13 03:54:22 2016-01-13 03:54:43 Again_______________________: 2016-01-13 03:59:43 2016-01-13 04:00:05 2016-01-13 04:00:25 2016-01-13 04:00:47 2016-01-13 04:01:09 2016-01-13 04:01:31 2016-01-13 04:01:53 2016-01-13 04:02:14 2016-01-13 04:02:36 Again_______________________: 2016-01-13 04:07:36 2016-01-13 04:07:58 2016-01-13 04:08:18 2016-01-13 04:08:40 2016-01-13 04:09:02 2016-01-13 04:09:24 2016-01-13 04:09:45 2016-01-13 04:10:07 2016-01-13 04:10:29 Again_______________________: 2016-01-13 04:15:29 2016-01-13 04:15:51 2016-01-13 04:16:11 2016-01-13 04:16:33 2016-01-13 04:16:55 2016-01-13 04:17:16 2016-01-13 04:17:38 2016-01-13 04:18:00 2016-01-13 04:18:22 Again_______________________: 2016-01-13 04:23:22 2016-01-13 04:23:44 2016-01-13 04:24:04 2016-01-13 04:24:26 2016-01-13 04:24:49 2016-01-13 04:25:11 2016-01-13 04:25:33 2016-01-13 04:25:55 2016-01-13 04:26:17 Again_______________________: 2016-01-13 04:31:17 2016-01-13 04:31:39 2016-01-13 04:31:59 2016-01-13 04:32:21 2016-01-13 04:32:43 2016-01-13 04:33:05 2016-01-13 04:33:26 2016-01-13 04:33:48 2016-01-13 04:34:10 Again_______________________: 2016-01-13 04:39:10 2016-01-13 04:39:32 2016-01-13 04:39:53 2016-01-13 04:40:15 2016-01-13 04:40:36 2016-01-13 04:40:58 2016-01-13 04:41:20 2016-01-13 04:41:42 2016-01-13 04:42:03 Again_______________________: 2016-01-13 04:47:03 2016-01-13 04:47:25 2016-01-13 04:47:45 2016-01-13 04:48:07 2016-01-13 04:48:29 2016-01-13 04:48:51 2016-01-13 04:49:13 2016-01-13 04:49:34 2016-01-13 04:49:56 Again_______________________: 2016-01-13 04:54:56 2016-01-13 04:55:18 2016-01-13 04:55:38 2016-01-13 04:56:00 2016-01-13 04:56:22 2016-01-13 04:56:44 2016-01-13 04:57:06 2016-01-13 04:57:28 2016-01-13 04:57:50 Again_______________________: 2016-01-13 05:02:50 2016-01-13 05:03:11 2016-01-13 05:03:32 2016-01-13 05:03:54 2016-01-13 05:04:15 2016-01-13 05:04:37 2016-01-13 05:04:59 2016-01-13 05:05:21 2016-01-13 05:05:43 Again_______________________: 2016-01-13 05:10:43 2016-01-13 05:11:05 2016-01-13 05:11:25 2016-01-13 05:11:47 2016-01-13 05:12:09 2016-01-13 05:12:30 2016-01-13 05:12:52 2016-01-13 05:13:14 2016-01-13 05:13:36 Again_______________________: 2016-01-13 05:18:36 2016-01-13 05:18:57 2016-01-13 05:19:18 2016-01-13 05:19:40 2016-01-13 05:20:02 2016-01-13 05:20:23 2016-01-13 05:20:45 2016-01-13 05:21:07 2016-01-13 05:21:29 Again_______________________: 2016-01-13 05:26:29 2016-01-13 05:26:51 2016-01-13 05:27:11 2016-01-13 05:27:33 2016-01-13 05:27:55 2016-01-13 05:28:16 2016-01-13 05:28:38 2016-01-13 05:29:00 2016-01-13 05:29:22 Again_______________________: 2016-01-13 05:34:22 2016-01-13 05:34:44 2016-01-13 05:35:04 2016-01-13 05:35:26 2016-01-13 05:35:47 2016-01-13 05:36:09 2016-01-13 05:36:31 2016-01-13 05:36:53 2016-01-13 05:37:15 Again_______________________: 2016-01-13 05:42:15 2016-01-13 05:42:37 2016-01-13 05:42:57 2016-01-13 05:43:19 2016-01-13 05:43:41 2016-01-13 05:44:02 2016-01-13 05:44:24 2016-01-13 05:44:46 2016-01-13 05:45:08 Again_______________________: 2016-01-13 05:50:08 2016-01-13 05:50:30 2016-01-13 05:50:50 2016-01-13 05:51:12 2016-01-13 05:51:34 2016-01-13 05:51:56 2016-01-13 05:52:17 2016-01-13 05:52:39 2016-01-13 05:53:01 Again_______________________: 2016-01-13 05:58:01 2016-01-13 05:58:23 2016-01-13 05:58:43 2016-01-13 05:59:05 2016-01-13 05:59:46 2016-01-13 06:00:08 2016-01-13 06:00:29 2016-01-13 06:00:51 2016-01-13 06:01:13 Again_______________________: 2016-01-13 06:06:13 2016-01-13 06:07:13 2016-01-13 06:07:34 2016-01-13 06:07:56 2016-01-13 06:08:18 2016-01-13 06:08:39 2016-01-13 06:09:01 2016-01-13 06:09:23 2016-01-13 06:09:45 Again_______________________: 2016-01-13 06:14:45 2016-01-13 06:15:07 2016-01-13 06:15:27 2016-01-13 06:15:49 2016-01-13 06:16:11 2016-01-13 06:16:33 2016-01-13 06:16:54 2016-01-13 06:17:16 2016-01-13 06:17:38 Again_______________________: 2016-01-13 06:22:38 2016-01-13 06:23:00 2016-01-13 06:23:20 2016-01-13 06:23:42 2016-01-13 06:24:04 2016-01-13 06:24:26 2016-01-13 06:24:47 2016-01-13 06:25:09 2016-01-13 06:25:31 Again_______________________: 2016-01-13 06:30:31 2016-01-13 06:30:53 2016-01-13 06:31:13 2016-01-13 06:31:35 2016-01-13 06:31:57 2016-01-13 06:32:19 2016-01-13 06:32:41 2016-01-13 06:33:03 2016-01-13 06:33:24 Again_______________________: 2016-01-13 06:38:24 2016-01-13 06:38:46 2016-01-13 06:39:07 2016-01-13 06:39:29 2016-01-13 06:39:50 2016-01-13 06:40:12 2016-01-13 06:40:34 2016-01-13 06:40:55 2016-01-13 06:41:17 Again_______________________: 2016-01-13 06:46:17 2016-01-13 06:46:39 2016-01-13 06:47:00 2016-01-13 06:47:22 2016-01-13 06:47:43 2016-01-13 06:48:05 2016-01-13 06:48:27 2016-01-13 06:48:49 2016-01-13 06:49:11 Again_______________________: 2016-01-13 06:54:11 2016-01-13 06:54:33 2016-01-13 06:54:53 2016-01-13 06:55:14 2016-01-13 06:55:36 2016-01-13 06:55:58 2016-01-13 06:56:19 2016-01-13 06:56:41 2016-01-13 06:57:21 Again_______________________: 2016-01-13 07:02:21 2016-01-13 07:02:43 2016-01-13 07:03:04 2016-01-13 07:03:25 2016-01-13 07:03:47 2016-01-13 07:04:09 2016-01-13 07:04:31 2016-01-13 07:04:53 2016-01-13 07:05:15 Again_______________________: 2016-01-13 07:10:15 2016-01-13 07:10:37 2016-01-13 07:10:57 2016-01-13 07:11:19 2016-01-13 07:11:41 2016-01-13 07:12:03 2016-01-13 07:12:25 2016-01-13 07:12:47 2016-01-13 07:13:09 Again_______________________: 2016-01-13 07:18:09 2016-01-13 07:18:31 2016-01-13 07:18:51 2016-01-13 07:19:13 2016-01-13 07:19:35 2016-01-13 07:19:57 2016-01-13 07:20:37 2016-01-13 07:20:59 2016-01-13 07:21:21 Again_______________________: 2016-01-13 07:26:21 2016-01-13 07:26:43 2016-01-13 07:27:03 2016-01-13 07:27:25 2016-01-13 07:27:47 2016-01-13 07:28:09 2016-01-13 07:28:31 2016-01-13 07:28:52 2016-01-13 07:29:14 Again_______________________: 2016-01-13 07:34:14 2016-01-13 07:34:36 2016-01-13 07:34:56 2016-01-13 07:35:18 2016-01-13 07:35:40 2016-01-13 07:36:02 2016-01-13 07:36:24 2016-01-13 07:36:46 2016-01-13 07:37:08 Again_______________________: 2016-01-13 07:42:08 2016-01-13 07:42:30 2016-01-13 07:42:50 2016-01-13 07:43:12 2016-01-13 07:43:34 2016-01-13 07:43:56 2016-01-13 07:44:18 2016-01-13 07:44:39 2016-01-13 07:45:01 Again_______________________: 2016-01-13 07:50:01 2016-01-13 07:50:23 2016-01-13 07:50:44 2016-01-13 07:51:04 2016-01-13 07:51:26 2016-01-13 07:51:48 2016-01-13 07:52:10 2016-01-13 07:52:32 2016-01-13 07:53:13 Again_______________________: 2016-01-13 07:58:13 2016-01-13 07:58:35 2016-01-13 07:58:56 2016-01-13 07:59:17 2016-01-13 07:59:39 2016-01-13 08:00:01 2016-01-13 08:00:23 2016-01-13 08:00:45 2016-01-13 08:01:07 Again_______________________: 2016-01-13 08:06:07 2016-01-13 08:06:29 2016-01-13 08:06:49 2016-01-13 08:07:11 2016-01-13 08:07:33 2016-01-13 08:07:55 2016-01-13 08:08:17 2016-01-13 08:08:39 2016-01-13 08:09:01 Again_______________________: 2016-01-13 08:14:01 2016-01-13 08:15:01 2016-01-13 08:15:21 2016-01-13 08:15:44 2016-01-13 08:16:05 2016-01-13 08:16:27 2016-01-13 08:16:50 2016-01-13 08:17:11 2016-01-13 08:17:33 Again_______________________: 2016-01-13 08:22:33 2016-01-13 08:22:55 2016-01-13 08:23:16 2016-01-13 08:23:38 2016-01-13 08:24:00 2016-01-13 08:24:22 2016-01-13 08:24:44 2016-01-13 08:25:06 2016-01-13 08:25:47 Again_______________________: 2016-01-13 08:30:47 2016-01-13 08:31:09 2016-01-13 08:31:29 2016-01-13 08:31:51 2016-01-13 08:32:13 2016-01-13 08:32:35 2016-01-13 08:32:57 2016-01-13 08:33:19 2016-01-13 08:33:41 Again_______________________: 2016-01-13 08:38:41 2016-01-13 08:39:03 2016-01-13 08:39:23 2016-01-13 08:40:04 2016-01-13 08:40:26 2016-01-13 08:40:48 2016-01-13 08:41:10 2016-01-13 08:41:32 2016-01-13 08:41:54 Again_______________________: 2016-01-13 08:46:54 2016-01-13 08:47:16 2016-01-13 08:47:36 2016-01-13 08:47:58 2016-01-13 08:48:43 2016-01-13 08:49:05 2016-01-13 08:49:27 2016-01-13 08:49:49 2016-01-13 08:50:11 Again_______________________: 2016-01-13 08:55:11 2016-01-13 08:55:33 2016-01-13 08:55:53 2016-01-13 08:56:16 2016-01-13 08:56:38 2016-01-13 08:57:01 2016-01-13 08:57:42 2016-01-13 08:58:04 2016-01-13 08:58:45 Again_______________________: 2016-01-13 09:03:45 2016-01-13 09:04:23 2016-01-13 09:04:43 2016-01-13 09:05:06 2016-01-13 09:05:28 2016-01-13 09:05:49 2016-01-13 09:06:12 2016-01-13 09:06:32 2016-01-13 09:06:53 Again_______________________: 2016-01-13 09:11:53 2016-01-13 09:12:54 2016-01-13 09:13:14 2016-01-13 09:13:36 2016-01-13 09:13:58 2016-01-13 09:14:20 2016-01-13 09:15:20 2016-01-13 09:15:42 2016-01-13 09:16:04 Again_______________________: 2016-01-13 09:21:04 2016-01-13 09:21:46 2016-01-13 09:22:07 2016-01-13 09:22:29 2016-01-13 09:23:10 2016-01-13 09:23:32 2016-01-13 09:23:54 2016-01-13 09:24:16 2016-01-13 09:24:38 So,写这篇博文其实可以总结为一句话:Driver建议用Firefox。
下载make好word2vec后,生成以下5个命令: compute-accuracy: distance: word2phrase:就是将词语拼成短语。 word2vec:丫应该是make后第一个执行的命令了,因为需要使用该命令训练语料库。我们首先需要准备好txt文本文件,里面全是用空格或Tab空开的词。然后通过以下代码生成*.bin文件,bin里面保存的值就是文档中词语和其对应的向量。千万不要以为,得到的bin文件就一定比input.txt小,超过100M的txt是这样,而且越大越是,但是对于20~50M的语料库而言就不一定了,起码我训练的时候是这样。 ./word2vec -train input.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1 word-analogy: 在Ubuntu15.04下安装Gensim: sudo apt-get install python-numpy python-scipy pip install gensim
1、前言 前两天开了两个进程,把Python抓回的数据链接并发写入Mysql中,结果显示出错。后来一查才知道需要自己设置锁,好生麻烦。这时PostgreSQL进入了我的视野,因为这家伙原生就是多进程的,但它是否支持多进程并发写入呢,还需要实际实验一下才知道。 2、安装PostgreSQL 第一步,进入官网:http://www.postgresql.org/,点击Download 第二步,选择操作系统对应的版本 第三步,我选择的Windows平台,因此下载说明该套件还包括视窗管理工具pgAdmin III。 继续下载,我选择的是64位,然后安装。接下来就是用pgAdmin创建数据库和表,老一套了,在此省略不表。 3、编写Python脚本 首先,需要安装Psycopg,这是Python访问PostgreSQL的链接库。官网上说windows版本需要下载安装包,其实也有pip的安装方式: 点击(此处)折叠或打开 pip install psycopg2 遗憾的是pip方式出现了问题,不知道是不是阅兵时的网络问题。 所以,我选择下载安装包: 4、测试结果 写入测试结果显示:可以实现两个进程对同一数据表的并发写入 但是,我也将同样的代码跑了一下Mysql,发现并发的很好。。。郁闷 所以,现在要更多的测试 # -*- coding: utf-8 -*- import threading,time #import psycopg2 import MySQLdb import string def multiGet(who): start = time.clock() #conn = psycopg2.connect(user='postgres',password='123456',database='links',host='localhost',port="5432") conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='rmrb') cursor = conn.cursor() for i in range(1000): sql = "INSERT INTO delta (ID,WHO) VALUES (NULL, '" + who + "' );" cursor.execute(sql) conn.commit() cursor.close() conn.close() end = time.clock() print who + " processing time is: %f s" % (end - start) task1 = threading.Thread(target = multiGet, args = ("a")) task1.start() task2 = threading.Thread(target = multiGet, args = ("b")) task2.start() 这时,出现了问题,主要是关键字段ID不能为空。所以,改善一下代码: # -*- coding: utf-8 -*- import threading,time #import psycopg2 import MySQLdb import string def multiGet(who): start = time.clock() #conn = psycopg2.connect(user='postgres',password='123456',database='links',host='localhost',port="5432") conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='rmrb') cursor = conn.cursor() for i in range(1000): if who == 'a': sql = "INSERT INTO delta (ID,WHO) VALUES (" + str(i) + ", '" + who + "' );" else: sql = "INSERT INTO delta (ID,WHO) VALUES (" + str(i+1000) + ", '" + who + "' );" cursor.execute(sql) conn.commit() cursor.close() conn.close() end = time.clock() print who + " processing time is: %f s" % (end - start) task1 = threading.Thread(target = multiGet, args = ("a")) task1.start() task2 = threading.Thread(target = multiGet, args = ("b")) task2.start() Mysql的结果如下: 上述结果是最后全部写入的,改成每条都commit呢?结果如下: b processing time is: 0.161019 sa processing time is: 0.162407 s 但是,这是InnoDB引擎的结果,数据量特大时,这个引擎超级慢。所以设置为MyISAM再试试。 a processing time is: 0.160377 sb processing time is: 0.159764 s 速度加快了,程度的调度其实还是分片,a一片然后b一片。 4、结论 看来Mysql足够,只是需要在关键字段的设置上做好功夫就可以。
Selenium包含:Selenium IDE、Selenium Remote Control、Selenium Grid和Selenium WebDriver。具体而言: 1. Selenium IDE作为Firefox上的一个插件,提供录制功能,个人观点,如果能手写代码,就不要用这个东西。 2. Selenium Remote Control是一个客户端/服务器系统,可以在本地或在其他电脑上控制Web浏览器,使用几乎任何编程语言和测试框架。 3. Selenium Grid 可以远程的控制到并在多个服务器上同时运行测试。 4. Selenium WebDriver可以在本地或远程计算机上的驱动浏览器。 Selenium支持多种语言,java/c#/python/ruby,但其本身是用Java开发的。 还有一篇文章也很好:http://www.cnblogs.com/fnng/p/3980093.html, http://web.jobbole.com/82621/
在Win8下经历惨痛的过程,耗费无数时间,结果依旧安装失败。 现在转战到Ubuntu14.10下。 首先,SuperScript需要Node.js,但版本最好不要高于0.10,我用apt-get install nodejs,安装上的是nodejs的0.10.20,但又发现报错说nodejs版本应该大于0.10.28好像。然后,删除掉原来安装的nodejs和npm: sudo apt-get aotoremove nodejssudo apt-get aotoremove npm 采用这篇博客的方案:http://my.oschina.net/blogshi/blog/260953 采用第一种方式,下载已经编译好的文件。 wget https://nodejs.org/dist/v0.10.40/node-v0.10.40-linux-x64.tar.gz 解压到/root cd node-v0.10.28-linux-x64/bin ls ./node -v 接下来,做软链接: ln -s /home/kun/mysofltware/node-v0.10.28-linux-x64/bin/node /usr/local/bin/node ln -s /home/kun/mysofltware/node-v0.10.28-linux-x64/bin/npm /usr/local/bin/npm 但是,直接用这里的npm依旧有问题,主要还是gyp的ERR。所以,回头google找gyp,有个人说:“following the right instructions on the node-gyp repository fixed it for me.”,因此,来到: https://github.com/TooTallNate/node-gyp 按照说明,安装gyp: lk@KevinLiu:~/node-v0.10.40-linux-x64/bin$ npm install -g node-gyp 然而,又是一对错误: npm ERR! Error: EACCES, mkdir '/usr/local/lib/node_modules' npm ERR! { [Error: EACCES, mkdir '/usr/local/lib/node_modules'] npm ERR! errno: 3, npm ERR! code: 'EACCES', npm ERR! path: '/usr/local/lib/node_modules', npm ERR! fstream_type: 'Directory', npm ERR! fstream_path: '/usr/local/lib/node_modules/node-gyp', npm ERR! fstream_class: 'DirWriter', npm ERR! fstream_stack: 所幸,有个提示: npm ERR! Please try running this command again as root/Administrator. 于是,改成如下的安装命令: lk@KevinLiu:~/node-v0.10.40-linux-x64/bin$ sudo npm install -g node-gyp 然后,gyp安装成功。 接着去弄SuperScript: lk@KevinLiu:~$ cd superscript-editor/ lk@KevinLiu:~/superscript-editor$ sudo npm install 也成功了。 但是在启动的时候,出现了问题: lk@KevinLiu:~/superscript-editor$ npm start > superscript-editor@0.1.7 start /home/lk/superscript-editor > node app { [Error: Cannot find module '../build/Release/bson'] code: 'MODULE_NOT_FOUND' } js-bson: Failed to load c++ bson extension, using pure JS version Error connecting to the MongoDB -- [Error: failed to connect to [localhost:27017]] 一个是没有安装MongoDB,一个是缺少c++ bson 我怀疑,bson问题和Mongo有关,所以先装好Mongo再说。自动apt-get速度太慢。 因此,先要把Ubuntu的源做成国内的。 根据yaya老兄的博文:http://chenrongya.blog.163.com/blog/static/8747419620143185103297/ 我换成了教育网的源,并且update一下。 接着: lk@KevinLiu:~$ sudo apt-get install mongodb-org 依旧超慢,20个小时。 怎么办呢?不能用Orglk@KevinLiu:~$ sudo apt-get install mongodb 于是,变成了秒装。lk@KevinLiu:~$ sudo /etc/init.d/mongodb start start: Job is already running: mongodb 现在又变成了这样: lk@KevinLiu:~$ npm start npm ERR! Error: ENOENT, open '/home/lk/package.json' npm ERR! If you need help, you may report this *entire* log, npm ERR! including the npm and node versions, at: npm ERR! <http://github.com/npm/npm/issues> npm ERR! System Linux 3.16.0-41-generic npm ERR! command "/usr/local/bin/node" "/usr/local/bin/npm" "start" npm ERR! cwd /home/lk npm ERR! node -v v0.10.40 npm ERR! npm -v 1.4.28 npm ERR! path /home/lk/package.json npm ERR! code ENOENT npm ERR! errno 34 npm ERR! npm ERR! Additional logging details can be found in: npm ERR! /home/lk/npm-debug.log npm ERR! not ok code 0 细细看,才发现当前目录下没有/home/lk/package.json这个文件,一搜发现原来在superscript下面,所以切换目录,进入superscript,再start。lk@KevinLiu:~/superscript-editor$ npm start > superscript-editor@0.1.7 start /home/lk/superscript-editor > node app SuperScript Community Editor. Listening at http://0.0.0.0:3000 Bot Name: testbot Switch or create a new bot by starting `BOT=<name> node app.js` GET / 200 398.915 ms - - GET /js/cytoscape.min.js 404 1.833 ms - 32 GET /favicon.ico 404 0.579 ms - 24 null POST /gambits/quick 200 30.540 ms - 34 POST /gambits/quick 200 266.547 ms - 16 null GET /topics 200 92.672 ms - - GET /js/cytoscape.min.js 404 0.755 ms - 32 GET /gambits 200 36.839 ms - - GET /js/cytoscape.min.js 404 0.726 ms - 32 GET /replies 200 39.346 ms - - GET /js/cytoscape.min.js 404 0.554 ms - 32 GET /knowledge 200 66.657 ms - - GET /js/cytoscape.min.js 404 0.546 ms - 32 GET / 200 77.627 ms - - GET /js/cytoscape.min.js 404 0.654 ms - 32 一切OK。看看我的机器人吧: 随后还有两项任务需要完成: 一是学习Node.js,有篇入门教程很好:从零开始nodejs系列文章,http://blog.fens.me/series-nodejs/ 二是学习SuperScript,http://superscriptjs.com/starter/quickstart 五岳之巅 于 武昌 桂子山 2015年7月31日,下午2点整
最近需要采集被试浏览过的网页记录,但发现3男3女都是使用360浏览器,极速和安全两款。这些浏览器都能看到浏览记录,然而存在两个问题:一是时间仅精确到分钟而不是秒,要知道1分钟内用户可能会浏览好几个网页;二是无法自行导出全部浏览记录。 于是,我就开始探索如何解决这两个问题。首先,到网上寻找历史记录信息,网友反馈说是保存在Document and Settings里名为History的文件,但我发现并不一定在这里。最好的方法是进入安装盘,如果浏览器装在C盘,那么就到C盘中搜索History这个名字,比较大的就是这个文件,比如一般都超过1M,而且没有扩展名哦。然后,用Sublime打开Hisory,去,都是16进制的耶。换成ultraedit再看,最开始一行字是Sqlite,明白了,这不是文本文件,而是数据库文件啊。 接下来,百度一下,原来Chrome有两个数据库,一个是HTML5的,一个是本地数据库,这个本地数据库就是Sqlite。所以,再从网上down下一个Navicat for SQLite试用版,打开History,发现Google真是记录了我们太多的东西了: 看看下载记录: 还有平时的搜索关键词也被保存了下来: 浏览器认为的分段: 以及访问记录及访问次数,停留时间等等都进行了记录: 最后,发现了一款小软件,用的基本原理就是读取Sqlite数据库,叫BrowsingHistoryView,可以直接导出Chrome、IE和Firefox的浏览记录,相当方便。
这个问题困扰我很久了,本来用Sublime编辑好Python文件,Ctrl+B即可,不知道怎么回事就是无法执行,控制台没有任何结果返回。最后,不得不回到Python IDLE的原始社会中。 今天,我又试着修改Preference下的配置文件,也是无果,百度一搜发现很多人都有这样的问题。于是,我就感觉是Sublime2的Bug,翻过去看看英文的评论,结果没有找到同样的症状。突然,我感觉到一丝凉意,难道是编码问题?于是,又赶紧核查了一下当前Python文件的位置,发现: 果不其然,赶紧把“我的”改为“my”,然后再Ctrl+B,哈哈,搞定。原来就是字符编码的问题,或者说就是中文路径的问题。。
最近一直在忙着给电商设计个性化推荐系统,反复思考用户视角下系统应该具备的交互能力和服务感知质量。抽空关注了刚刚结束的世界互联网大会,在写了两篇吐槽感十足的博文后心想着我这颗老心脏可能无法再波起涟漪了。谁知某个慵懒的午后,CU发来消息告知有一场名为“可靠性能管理的第一步:真实用户体验”的在线讲座,出于对在线教育的好奇,也出于与毕业论文异曲同工的用户体验,我打算进去逛一下。 刚登陆的时候随着音视频的调试杂音频出、视频经常定格,我原本以为我又将无聊地耗费掉30分生命值。然而,随着课程的深入,才渐渐明白了我真是“以小人之心度君子之腹”,Compuware提出的APM解决方案的确让人眼前一亮,不愧为大厂出品,出发点就已然高人一等,心中实在忍不住叫好。从用户体验管理(UEM)到移动监测,从流媒体检测到深度应用交易管理,从数据中心真实用户检测到深度应用交易诊断与回归管理等等,无一不是对电商360的全面保护。这种保护的力度之强,程度之深真是比较少见。 就个人感觉而言,Compuware系统的强大还是根源于对用户的重视。这里用户有两层意思,一个是消费者,一个是电商企业。对于普通消费者,在网站动用了N多资源之后终于被诱导而来,兴致勃勃地浏览后却放弃了购买,为什么?也许是网站某项服务超时,也许是购买路径设置矛盾,亦或是某个页面让用户一下子失去了信心。原因可能会有很多种,但以前是无法具体知晓或很快知晓的,然而UEM却可以全天候实时监控所有业务页面,对产生的问题进行记录并轻而易举地发现问题出现的根源,从而使得电商在很短时间内做出及时而又正确的回应。对于电商企业,Compuware可不只是个UEM这么简单,它可以保护和支持企业对外、对内服务的方方面面,全平台、全天候、全服务和全可视化展现的特点正是其“首屈一指”敏捷能力的写照。 时间就是电商的生命。对一般用户而言,0.1秒是瞬时、可接受的响应,类似使用Baidu搜索的体验。响应时间为2至4秒时,互动开始变慢,客户满意度风险增大。超过10秒用户将铁定离开。由于传统的应用性能管理采用的是被动式而非主动式,只能在问题对客户产生影响后才能加以识别,因此难以奏效。事实上大多数应用访问问题都是由客户报告的,而不是由主动监测所发现。如果您的公司还是这种情况,那么您真的可以看看Compuware在做的事情,未必购买但一定要好好学习。
本文是博主博士毕业论文《基于屏幕视觉热区的交互收敛式实时个性化推荐方法》中第3章的部分内容,只是本人思索的记录而已。博士毕业答辩尚未进行,论文也未提交,因此请勿转载,谢谢。 在人类的300多万年的进化长河中,从古至今产生、消亡、存续着诸多伟大的文明之光。正对工具的制造和使用,让人类从动物界中分类出来,从被动生存演进到主动改造世界的洪流之中;也正是实践中的工具而非形而上的生产力,让人成为了真正的人。站在工具的视角重新审视,人类的历史就是一部对人的工具化发展史。 人类的活动分为物理和心理两种类型。自古以来,人类的活动便受制于时间和空间而“不自由”。对自由的向往与追求无时无刻不在激励着人类扩展活动的范围。不幸的是,不论是履足远征还是心灵思考,都无法在更远的位置更早(或更晚)的时间远行。纵然人类自身本无法实现,但是工具的出现、理论的提高及技艺的提升使得人类的远足之梦得以实现。渐渐地,工具对人类的器官实现了成功延展:棍棒和弓弩延展了双手,汽车、火车、轮船和飞机延展了双腿,望远镜、显微镜和电视机延展了双眼,广播、电话延展了双耳,各种传感器的出现又延展了人们的鼻子和皮肤 。正在人们就此满足地欣喜欢呼之时,互联网的出现彻底延展了人类的大脑,它将所有的一切串联起来正在改写着人类的历史。 个性化推荐系统的出现并非偶然,从古人狩猎的猎物选择到皇室菜肴烹饪,从刑侦破案到杂志出版,从汽车制造到时尚工业,处处都浮现着个性化推荐的“原始”身形。只是进入互联网时代后,随着宽带、云计算和大数据分析等技术的发展,在运算和存储的工具性能力跃入新的层级之后,推荐系统才达到了前所未有的“个性化”程度。纵然,个性化推荐产生的直接原因出自人类对信息过载问题的解决之中,但是其产生的根本土壤则是对自身肉体上和精神上工具化延伸的不懈最求。 个性化推荐系统本质是一个“人”的问题,而并非全部是计算的问题。因此,与“人”有关,特别是与“人”的心理活动和行为活动有关的学科都是其理论发源的沃土。对个性化推荐的严肃思考,需要冲破计算机科学的牢笼;对个性化推荐系统理论的建构,需要从更多的学科中汲取养料。
作者:Glen.He 出处:http://www.cnblogs.com/puresoul/ 1.1 下载selenium2.0的包 官方download包地址:http://code.google.com/p/selenium/downloads/list 官方User Guide: http://seleniumhq.org/docs/ 官方API: http://selenium.googlecode.com/git/docs/api/java/index.html 1.2.1 用webdriver打开一个浏览器 打开firefox浏览器: WebDriver driver = new FirefoxDriver(); 打开IE浏览器 WebDriver driver = new InternetExplorerDriver (); 打开HtmlUnit浏览器 WebDriverdriver = new HtmlUnitDriver(); 打开chrome浏览器 WebDriverdriver = new ChromeDriver(); 1.2.2 最大化浏览器 WebDriver driver = new FirefoxDriver(); driver.manage().window().maximize(); 1.2.3 关闭浏览器 WebDriver driver = new FirefoxDriver(); driver.close(); driver.quit(); 1.3 打开测试页面 driver.get("http://www.google.com"); driver.navigate().to("http://www.baidu.com/"); P.S.navigate方法会产生1个Navigator对象,其封装了与导航相关的一些方法,比如前进后退等 1.4 页面元素定位 Webdriver提供下面两种方法来定位页面元素,参数是By对像,最常用是By.id和By.name查找。 findElement 定位某个元素,如果没有找到元素会抛出异常:NoSuchElementException findElements 定位一组元素 例如需要定位如下元素: By.id: WebElement element = driver.findElement(By.id("passwd-id")); By.name: WebElement element = driver.findElement(By.name("passwd")); By.xpath: WebElement element =driver.findElement(By.xpath("//input[@id='passwd-id']")); By.className WebElement element = driver.findElement(By.className("input_class")); By.cssSelector WebElement element = driver.findElement(By.cssSelector(".input_class")); By.linkText: //通俗点就是精确查询 WebDriver driver = new FirefoxDriver(); driver.get("http://www.baidu.com/"); WebElement element = driver.findElement(By.linkText("百科")); By.partialLinkText: //这个方法就是模糊查询 WebDriver driver = new FirefoxDriver(); driver.get("http://www.baidu.com/"); WebElement element = driver.findElement(By.partialLinkText("hao")); By.tagName: WebDriver driver = new FirefoxDriver(); driver.get("http://www.baidu.com/"); String test= driver.findElement(By.tagName("form")).getAttribute("name"); System.out.println(test); 1.5 如何对页面元素进行操作 1.5.1 输入框(text field or textarea) WebElement element = driver.findElement(By.id("passwd-id")); element.sendKeys(“test”);//在输入框中输入内容: element.clear(); //将输入框清空 element.getText(); //获取输入框的文本内容: 1.5.2下拉选择框(Select) Select select = new Select(driver.findElement(By.id("select"))); select.selectByVisibleText(“A”); select.selectByValue(“1”); select.deselectAll(); select.deselectByValue(“1”); select.deselectByVisibleText(“A”); select.getAllSelectedOptions(); select.getFirstSelectedOption(); 1.5.3单选项(Radio Button) WebElement radio=driver.findElement(By.id("BookMode")); radio.click(); //选择某个单选项 radio.clear(); //清空某个单选项 radio.isSelected(); //判断某个单选项是否已经被选择 1.5.4多选项(checkbox) WebElement checkbox = driver.findElement(By.id("myCheckbox.")); checkbox.click(); checkbox.clear(); checkbox.isSelected(); checkbox.isEnabled(); 1.5.5按钮(button) WebElement btn= driver.findElement(By.id("save")); btn.click(); //点击按钮 btn.isEnabled (); //判断按钮是否enable 1.5.7弹出对话框(Popup dialogs) Alert alert = driver.switchTo().alert(); alert.accept(); //确定 alert.dismiss(); //取消 alert.getText(); //获取文本 1.5.8表单(Form) Form中的元素的操作和其它的元素操作一样,对元素操作完成后对表单的提交可以: WebElement approve = driver.findElement(By.id("approve")); approve.click(); 或 approve.submit();//只适合于表单的提交 1.5.9上传文件 上传文件的元素操作: WebElement adFileUpload =driver.findElement(By.id("WAP-upload")); String filePath = "C:\test\\uploadfile\\media_ads\\test.jpg"; adFileUpload.sendKeys(filePath); 1.6 Windows 和 Frames之间的切换 driver.switchTo().defaultContent(); //返回到最顶层的frame/iframe driver.switchTo().frame("leftFrame"); //切换到某个frame: driver.switchTo().window("windowName"); //切换到某个window 1.7 调用Java Script Web driver对Java Script的调用是通过JavascriptExecutor来实现的,例如: JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("JS脚本"); 1.8 超时设置 WebDriver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //识别元素时的超时时间 driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); //页面加载时的超时时间 driver.manage().timeouts().setScriptTimeout(10, TimeUnit.SECONDS); //异步脚本的超时时间
出征万里征途,艰辛苦楚。狼烟萧萧,战旗挥舞。 脚踏骸骨,刃染赤珠。遥望生死,无畏黄土。 荒冥天地,还看我主。 2014-06-24 于武昌,桂子山
2013年1月11日 18:08:27 闲着无聊,说说指针吧。 指针其实很简单,就是个地址。它有三个基本属性:地址属性,步长属性,数据格式化。地址属性是其最基本的属性,也是指针的定义所在。而常用的则是其步长属性和数据格式化。具体解析如下。 地址属性: 比如你定义一个变量: U16 u16Temp; 那么软件就会为你所定义的变量分配一个地址,具体这个地址在哪里?依据你所定义的变量的类型,如果是全局变量或静态(二者本质是一样的),那就在全局区中,如果是局部变量,那就在函数的栈中。可以通过&u16Temp来得到其具体的值。这是其地址属性。 步长属性: 这里的步长属性是指指针在参与运算过程中,主要是加减运算,进行一个单位的加减时,其所能跨越的地址范围。比如,定义一个指针变量如下: U16* u16pPointer = 0X12345678; 当你执行u16pPointer++时,其值变会变成了0X1234567A,注意:是从8变到A,加了2,为什么加2?因数U16占用两个字节,那么指针运算一次,其步长就是2个字节。如果你定义成U32,那么步长就是4个字节了。如果两个指针做差运算,那么得到是什么呢?比如U16* u16P1 = 0Xaaa0; U16* u16P2= 0XAAAA,如果u16P2-u16P1=?,如果直接理解,得到值将是0XAAAA-0XAAA0=A, 这样分析错了,为什么?指针另时,编译器会乘上步长,与此类似,这里也会除以步长,也就是说,两个指针相差,你得到的将是步长值,所以正确的结果是A/2=5. 数据格式化 这是对步长属性的引申,比如你定义了一个结构体, typedef struct { U16 Data1; U8 Data2; U8 Data3; }tStrTest; 这里定义了个结构体,你定义一个指针U16* u16P1=0X12345678,显然其步长是2,如果你对其做强制转化,如下所示: (tStrTest*)u16P1,那么0X12345678开始的数据将会被编译器解析为一个结构体,也就是说,你可以使用0X12345678~0X1234567B在编译器看来,就是一个结构体, 前面两个字节是Data1,后面两个字节分别是Data2和Data3.这个技巧很有用,可以将其叫做数据流的解析,比如,在网络编程中,你将接收到的数据放到一个数组中,然后定义一个IP头结构体去解析这个数组,那么就可以对数据进行解析了. 脑子比较乱,文笔也不好,所以写得也比较乱,如果有错误的地方,欢迎指出.
CU博主西方失败2913312169,在博文《声明数组参数》中抛出了C语言指针的函数参数传递问题,原文链接如下: http://blog.chinaunix.net/uid-29455636-id-4214932.html 这是中国学生的老问题了,怪我们老师没教好,所以现在特地详细解释一下。首先要说明几个基本原则: 1、数组名是地址常量,也即指针常量。但通常省略了一个限定范围,即函数体内。函数体内,如main或自定义函数等体内定义的数组名都是地址常量。不能用++或--这类的自增或自减运算符,当然也不能用a+=1,毕竟常量不能作为左值。这是理解指针的第一个前提。 2、*与&为互逆的两个运算符,分为是取值和取址。对于int a = 0;那么&a就是a变量的地址,而*(&a)就是按变量类型int取出a变量存放值的空间中的值。 3、C语言里指针有两级,一级指针(指向地址的指针)和二级指针(指向地址指针的指针),都是指向地址但层次不同,一级和二级指针可以指向同一地址,但方向不同。例如:a[3][3]。a是二级指针,a+1向下跳一行,(*a)是一级指针,(*a)+1向后跳一列。对二级指针取值,就把指针指向也即移动单位进行了变换(实质上是完成了一种特殊类型的转换),*a就等于&(a[0][0])。这是理解指针的第二个前提。需要注意的是,所谓的两级指针并非链表那种你连我,我连他,千万别误以为链表中的第一个是一级指针,第二个是二级指针,第三个指针是三级指针,其实链表里的链接指向指针都属于一级指针。 4、好了开始说关键之处吧,在函数定义时,参数的作用是接收其它传入值,不管这个值是否为指针。当然了,形参可以是变量,或缺省常量,如果是缺省常量,只能定义在参数列表的后面。你这里的定义并非缺省常量,所以该形参是一个变量。这就是为什么说在作为参数时, 数组和指针是等价的,因为发生拷贝出现了值传递,const直接转为了non-const。于是,可以认为函数形参定义的括号内并非严格属于函数体内。 我专门写了一个小程序,如下: 请你思考下并自测一下,为什么是下面这个答案? 呵呵,虽然这个例子有点难度,但希望本贴对你真正有用。有什么想法,咱们一起讨论。如有不正确之处,也请指正。
ICTCLAS是张华平博士的杰作,在多版演进后,于2014年释出的新版本,当然新版改名叫做NLPIR了,支持中英文分词,词性标注,关键语义提取,微博分词,修缮了部分bug,非商用永久免费。其中,对C/C++/C#/JAVA语言的支持都已非常完善,但我用的是Python,之前选择的是SCWS组件,但在实际使用过程中感觉SCWS分词和词性标注质量并不如NLPIR好,因此打算换用NLPIR。 第一个问题是如何安装NLPIR。由于NLPIR需要首先安装swig,我首先试了“easy_install swig”和“pip install swig”都失败了。然后登陆swig官网,下载win32的包。 sourceforege上的地址如下:http://sourceforge.net/projects/swig/files/swigwin/swigwin-3.0.0/swigwin-3.0.0.zip/download?use_mirror=ncu 下载后解压到C:\Program Files\swigwin,并在系统path中添加这一路径。 快捷键win+r,cmd命令后打开命令行窗口,输入swig,出现“Must specify an input file. Use -help for available options.”,说明swig已安装成功。如下图所示: 接下来,就需要下载安装我们的主角NLPIR了。 虽然可以简单地从微盘下载,如这里: 但运气不佳,我现在访问微盘时,正好赶上“扫黄打非”,而看不到他人的共享文件: 所以,我就去GitHub上下载。 打开浏览器,进入https://github.com/killuahzl/python-nlpir。 在下图所示位置,下载zip包。 未完待续。。。
毋庸置疑,LibSVM是台湾牛人为世界机器学习的卓越贡献之一。一般都是基于Matlab的,其实LibSVM也可以用Python跑。 第一步,确定本机Python的版本: 32位的最易配置,哈哈,我的机器就是这么的古董。64位的童鞋请Google。 第二步,到官网http://www.csie.ntu.edu.tw/~cjlin/libsvm/,来下载LibSVM软件包,我选择的是zip包。 第三步,将zip包解压到一个特定位置,我放到了C:盘根目录,当然也可以放到program files中。 第四步,就可以测试一下LibSVM是否可用了,打开Python IDE,输入以下代码: 能够看到输出,84%的分类准确性。 第五步,使用我的个人数据 libsvm的数据格式如下: 第一列代表标签,第二列是第一个特征值,第三列是第二个特征值。所以,先要把数据按规定格式整理好。然后开始训练。 import os import sys os.chdir('C:\libsvm-3.17\python') from svmutil import * y, x = svm_read_problem('../lkagain.txt') m = svm_train(y[:275], x[:275], '-c 5') y, x = svm_read_problem('../lk2.txt') p_label, p_acc, p_val = svm_predict(y[0:], x[0:], m) print p_label print p_acc print p_val 第六步,Python接口 在libsvm-3.16的python文件夹下主要包括了两个文件svm.py和svmutil.py。 svmutil.py接口主要包括了high-level的函数,这些函数的使用和LIBSVM的MATLAB接口大体类似 svmutil中主要包含了以下几个函数: svm_train() : train an SVM model svm_predict() : predict testing data svm_read_problem() : read the data from a LIBSVM-format file. svm_load_model() : load a LIBSVM model. svm_save_model() : save model to a file. evaluations() : evaluate prediction results. 本文参考了http://blog.csdn.net/lqhbupt/article/details/8599295,在此感谢xmjdh。
由于最近手头项目需要,我查阅了Python相关的机器学习库。我将不断地更新本贴,从而详细说明各个库的优劣。一、前提 在Pthon下做机器学习,需要科学计算包和绘图库的支持,科学计算则是NumPy或SciPy,似乎NumPy更流行些。画图工具包则必定为matplotlib。这些都是开源、免费使用的,选择这些库主要的原因是做线性代数中的矩阵计算极为便利,而且效率比自己开发高的多。二、机器学习库(1)scikit-learn [http://scikit-learn.org/] Python下做机器学习,首推scikit-learn。该项目文档齐全、讲解清晰,功能齐备,使用方便,而且社区活跃。 (2)Orange [http://orange.biolab.si/] 机器学习是其的功能之一,主要还是侧重数据挖掘,可以用可视化语言或Python进行操作,拥有机器学习组件,还具有生物信息学以及文本挖掘的插件。 (3)shogun [http://shogun-toolbox.org/] shogun,非日本的老外弄的一个机器学习库,还专门配了一个我们能看懂的日文名“将军”(是日本幕府时代的将军)。文档齐全,开发活跃,更新快,运算速度也很快。主攻大尺度的核函数,尤其是大尺度核函数下的SVM。具有很多SVM的高级用法,比如多核配用等。支持Python、R、C++、Matlab等语言。 (4)其它 A.pyml(a python module for machine learning,支持svm/knn/k-means==) http://mlpy.sourceforge.net/ B.milk(python的机器学习工具包,主要是针对监督学习,包括svm/knn/决策树) http://pypi.python.org/pypi/milk/ 本文参考了oschina.net及http://www.cnblogs.com/wuren/archive/2013/03/27/2985352.html
一、分词 SCWS 中文分词v1.2.2 开源免费的中文分词系统,PHP分词的上乘之选!http://www.xunsearch.com/scws/download.php#dll 首先,根据PHP的版本下载php_scws.dll文件,进行安装: 1. 根据您当前用的 PHP 版本,下载相应已编译好的 php_scws.dll 扩展库。 2. 将下载后的 php_scws.dll 放到 php 安装目录的 extensions/ 目录中去(通常为:X:/php/extensions/或 X:/php/ext/)。我用的XAMPP,所以 3. 建立一个本地目录放规则集文件和词典文件,建议使用:C:/program files/scws/etc 4. 从 scws 主页上下载词典文件,解压后将 *.xdb 放到上述目录中 5. 从 scws 主页上下载规则集文件,解压后将 *.ini 放到第 3 步建立的目录 规则集文件压缩包:http://www.xunsearch.com/scws/down/rules.tgz 解压后有三个文件分别为 rules.ini rules.utf8.ini rules_cht.utf8.ini 将三件文件拷到第 3 步所述的目录中 6. 修改 php.ini 通常位于 C:/windows/php.ini 或 C:/winnt/php.ini 之类的目录, 在 php.ini 的末尾加入以下几行:[scws] ; ; 注意请检查 php.ini 中的 extension_dir 的设定值是否正确, 否则请将 extension_dir 设为空, ; 再把 php_scws.dll 指定为绝对路径。 ; extension = php_scws.dll scws.default.charset = gbk scws.default.fpath = "c:/program files/scws/etc" 5. 重开 web 服务器即可完成。 以上都是按照官方文档照办,照猫画虎即可。在phpinfo()中可以看到: 嗯,这就是SCWS装好了。接下来就看看如何用PHP调用它。二、PHP下分词工具SCWS的使用 ?php header('Content-Type:text/html; charset=utf-8'); $so = scws_new(); $so->set_charset('utf8'); $so->send_text("2、我一向理解不了母亲不同意儿子找的对象是一种什么心理。嫌身高?嫌体重?嫌长相?嫌学历?嫌单亲家庭?"); $i = 0; while ($tmp = $so->get_result()) { foreach($tmp as $K=>$val){ echo $val['word'].' '.$val['attr'].""; } } $so->close(); ?> 主要是用scws_new()实例化一个对象so,然后用so的send_text()方法接收字符串,并通过关键的get_result()得到返回的结果。 关于中文词的词性缩写,请参考如下介绍:n.名词v.动词adj.形容词adv.副词clas.量词echo.拟声词stru.结构助词aux.助词coor.并列连词conj.连词suffix.后缀prefix.前缀prep.介词pron.代词ques.疑问词num.数词idiom.成语
京东图书评论有非常丰富的信息,这里面就包含了购买日期、书名、作者、好评、中评、差评等等。以购买日期为例,使用Python + Mysql的搭配进行实现,程序不大,才100行。相关的解释我都在程序里加注了: from selenium import webdriver from bs4 import BeautifulSoup import re import win32com.client import threading,time import MySQLdb def mydebug(): driver.quit() exit(0) def catchDate(s): """页面数据提取""" soup = BeautifulSoup(s) z = [] global nowtimes m = soup.findAll("div",class_="date-buy") for obj in m: try: tmp = obj.find('br').contents except Exception, e: continue if(tmp != ""): z.append(tmp) nowtimes += 1 return z def getTimes(n,t): """获取当前进度""" return "当前进度为:" + str(int(100*n/t)) + "%" #———————————————————————————————————| 程序开始 |————————————————————————————————— #确定图书大类 cate = {"3273":"历史","3279":"心理学","3276":"政治军事","3275":"国学古籍","3274":"哲学宗教","3277":"法律","3280":"文化","3281":"社会科学"} #断点续抓 num1 = input("bookid:") num2 = input("pagenumber:") #生成图书大类链接,共需17355*20 = 347100次 totaltimes = 347100.0 nowtimes = 0 #开启webdirver的PhantomJS对象 #driver = webdriver.PhantomJS() driver = webdriver.Ie('C:\Python27\Scripts\IEDriverServer') #driver = webdriver.Chrome('C:\Python27\Scripts\chromedriver') #读出Mysql中的评论页面,进行抓取 # 连接数据库 try: conn = MySQLdb.connect(host='localhost',user='root',passwd='',db='jd') except Exception, e: print e sys.exit() # 获取cursor对象 cursor = conn.cursor() sql = "SELECT * FROM booknew ORDER BY pagenumber DESC" cursor.execute(sql) alldata = cursor.fetchall() flag = 0 flag2 = 0 # 如果有数据返回就循环输出,http://club.jd.com/review/10178500-1-154.html if alldata: for rec in alldata: #rec[0]--bookid,rec[1]--cateid,rec[2]--pagenumber if(rec[0] != str(num1) and flag == 0): continue else: flag = 1 for p in range(num2,rec[2]): if(flag2 == 0): num2 = 0 flag2 = 1 p += 1 link = "http://club.jd.com/review/" + rec[0] + "-1-" + str(p) + ".html" #抓网页 driver.get(link) html = driver.page_source #抓评论 buydate = catchDate(html) #写入数据库 for z in buydate: sql = "INSERT INTO ljj (id, cateid, bookid, date) VALUES (NULL, '" + rec[0] + "','" + rec[1] + "','" + z[0] + "');" try: cursor.execute(sql) except Exception, e: print e conn.commit() print getTimes(nowtimes,totaltimes) driver.quit() cursor.close() conn.close()
1、检视Python版本 如果尚未安装Python,那么你可以到Python官网进行下载: For the MD5 checksums and OpenPGP signatures, look at the detailed Python 3.3.3 page: Python 3.3.3 Windows x86 MSI Installer (Windows binary -- does not include source) Python 3.3.3 Windows X86-64 MSI Installer (Windows AMD64 / Intel 64 / X86-64 binary [1] -- does not include source) Python 3.3.3 Mac OS X 64-bit/32-bit x86-64/i386 Installer (for Mac OS X 10.6 and later [2]) Python 3.3.3 Mac OS X 32-bit i386/PPC Installer (for Mac OS X 10.5 and later [2]) Python 3.3.3 compressed source tarball (for Linux, Unix or Mac OS X) Python 3.3.3 xzipped source tarball (for Linux, Unix or Mac OS X, better compression) For the MD5 checksums and OpenPGP signatures, look at the detailed Python 2.7.6 page: Python 2.7.6 Windows Installer (Windows binary -- does not include source) Python 2.7.6 Windows X86-64 Installer (Windows AMD64 / Intel 64 / X86-64 binary [1] -- does not include source) Python 2.7.6 Mac OS X 64-bit/32-bit x86-64/i386 Installer (for Mac OS X 10.6 and later [2]) Python 2.7.6 Mac OS X 32-bit i386/PPC Installer (for Mac OS X 10.3 and later [2]) Python 2.7.6 compressed source tarball (for Linux, Unix or Mac OS X) Python 2.7.6 xzipped source tarball (for Linux, Unix or Mac OS X, better compression) 或者,你嫌慢,可以找几个离得近的: Python for Windows 3.2.2 电信下载: 本地电信1本地电信2 网通下载: 本地网通 专用下载: 迅雷下载快车下载 安装,很简单,一步一步NEXT就好了,默认装到C:\python下,我觉得这个路径就很好。2、安装Python-mysql库 我试了下,我机器上使用easy_install安装MySQLdb出错。 适才发现这是个名称错误的问题,国外友人已经回答了,有如下方案: windows解决方案:easy_install MySQL-python 或者 pip install MySQL-pythonLinux解决方案:apt-get install python-dev 或者 yum install python-devel 不过,我用的最笨的方法,到http://www.cr173.com/soft/22957.html这里下载了MySQL-python.rar安装包进行安装。3、Python-mysql主要操作 主要操作,可以参考如下代码(转自Sephiroth): #-*- encoding: gb2312 -*- import os, sys, string import MySQLdb # 连接数据库 try: conn = MySQLdb.connect(host='localhost',user='root',passwd='xxxx',db='test1') except Exception, e: print e sys.exit() # 获取cursor对象来进行操作 cursor = conn.cursor() # 创建表 sql = "create table if not exists test1(name varchar(128) primary key, age int(4))" cursor.execute(sql) # 插入数据 sql = "insert into test1(name, age) values ('%s', %d)" % ("zhaowei", 23) try: cursor.execute(sql) except Exception, e: print e sql = "insert into test1(name, age) values ('%s', %d)" % ("张三", 21) try: cursor.execute(sql) except Exception, e: print e # 插入多条 sql = "insert into test1(name, age) values (%s, %s)" val = (("李四", 24), ("王五", 25), ("洪六", 26)) try: cursor.executemany(sql, val) except Exception, e: print e #查询出数据 sql = "select * from test1" cursor.execute(sql) alldata = cursor.fetchall() # 如果有数据返回,就循环输出, alldata是有个二维的列表 if alldata: for rec in alldata: print rec[0], rec[1] cursor.close() conn.close() 相关资料: 1.引入MySQLdb库 import MySQLdb2.和数据库建立连接 conn=MySQLdb.connect(host="localhost",user="root",passwd="sa",db="mytable",charset="utf8") 提供的connect方法用来和数据库建立连接,接收数个参数,返回连接对象. 比较常用的参数包括: host:数据库主机名.默认是用本地主机. user:数据库登陆名.默认是当前用户. passwd:数据库登陆的秘密.默认为空. db:要使用的数据库名.没有默认值. port:MySQL服务使用的TCP端口.默认是3306. charset:数据库编码. 更多关于参数的信息可以查这里 http://mysql-python.sourceforge.net/MySQLdb.html 然后,这个连接对象也提供了对事务操作的支持,标准的方法 commit() 提交 rollback() 回滚 3.执行sql语句和接收返回值 cursor=conn.cursor() n=cursor.execute(sql,param) 首先,我们用使用连接对象获得一个cursor对象,接下来,我们会使用cursor提供的方法来进行工作.这些方法包括两大类:1.执行命令,2.接收返回值 cursor用来执行命令的方法: callproc(self, procname, args):用来执行存储过程,接收的参数为存储过程名和参数列表,返回值为受影响的行数 execute(self, query, args):执行单条sql语句,接收的参数为sql语句本身和使用的参数列表,返回值为受影响的行数 executemany(self, query, args):执行单条sql语句,但是重复执行参数列表里的参数,返回值为受影响的行数 nextset(self):移动到下一个结果集 cursor用来接收返回值的方法: fetchall(self):接收全部的返回结果行. fetchmany(self, size=None):接收size条返回结果行.如果size的值大于返回的结果行的数量,则会返回cursor.arraysize条数据. fetchone(self):返回一条结果行. scroll(self, value, mode='relative'):移动指针到某一行.如果mode='relative',则表示从当前所在行移动value条,如果mode='absolute',则表示从结果集的第一行移动value条. 下面的代码是一个完整的例子. #使用sql语句,这里要接收的参数都用%s占位符.要注意的是,无论你要插入的数据是什么类型,占位符永远都要用%s sql="insert into cdinfo values(%s,%s,%s,%s,%s)" #param应该为tuple或者list param=(title,singer,imgurl,url,alpha) #执行,如果成功,n的值为1 n=cursor.execute(sql,param) #再来执行一个查询的操作 cursor.execute("select * from cdinfo") #我们使用了fetchall这个方法.这样,cds里保存的将会是查询返回的全部结果.每条结果都是一个tuple类型的数据,这些tuple组成了一个tuple cds=cursor.fetchall() #因为是tuple,所以可以这样使用结果集 print cds[0][3] #或者直接显示出来,看看结果集的真实样子 print cds #如果需要批量的插入数据,就这样做 sql="insert into cdinfo values(0,%s,%s,%s,%s,%s)" #每个值的集合为一个tuple,整个参数集组成一个tuple,或者list param=((title,singer,imgurl,url,alpha),(title2,singer2,imgurl2,url2,alpha2)) #使用executemany方法来批量的插入数据.这真是一个很酷的方法! n=cursor.executemany(sql,param) 4.关闭数据库连接 需要分别的关闭指针对象和连接对象.他们有名字相同的方法 cursor.close() conn.close() 四步完成,基本的数据库操作就是这样了.下面是两个有用的连接 MySQLdb用户指南: http://mysql-python.sourceforge.net/MySQLdb.html MySQLdb文档: http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb-module.html 5 编码(防止乱码) 需要注意的点: 1 Python文件设置编码 utf-8 (文件前面加上 #encoding=utf-8) 2 MySQL数据库charset=utf-8 3 Python连接MySQL是加上参数 charset=utf8 4 设置Python的默认编码为 utf-8 (sys.setdefaultencoding(utf-8) 注:MySQL的配置文件设置也必须配置成utf8设置 MySQL 的 my.cnf 文件,在 [client]/[mysqld]部分都设置默认的字符集(通常在/etc/mysql/my.cnf): [client] default-character-set = utf8 [mysqld] default-character-set = utf8 (本节引自http://drizzlewalk.blog.51cto.com/2203401/448874)
大数据的好处经常提及我就不说了,我想谈谈反思,算作冷思考吧: 1、大数据源于一个概念,但发展至今已经形成了以技术为基础的商业体系,并慢慢形成产业生态圈。这与前几年的“云计算”发展脉络如出一辙。云计算和大数据热的背后,是行业的萧条。回想十多年前IT蓬勃发展的黄金时代,不需概念提携就已然能够迅猛发展。如今,IT产业步入中年期,不来两剂猛药,怕是步履太过缓慢。 2、大数据的实践,并非无源之水天上来,它依赖于企事业已有的信息化基础。我国很多企业和政府机构中,电脑是买了,系统是上了,但太过低端,大多都是只是业务流程的无纸化复刻而已,无纸化是信息化最低端的一个层次,不过实事求是地说,这就是现状。对于“大”数据而言,这些部门内的数据就是“小”数据。数据虽小,但也有价值,遗憾的是基本的完整统计分析功能都不一定具备,更高级的智能分析就更别提了;数据虽小,但如果部门内部的数据能够汇合起来,交叉关联,就能变成“中”数据,部门间的数据一起汇总,就能形成“大”数据。我国幅员辽阔,人口众多,办事机构数量也为世界之首。数据量多得是,但到处都是孤岛,处处都是竖井。大数据概念虽热,但更需脚踏实地稳步前行,不能刚学会走、立刻就想跑。 3、大数据的运维需要复合型人才,中国教育提供的“合格产品”太少。既懂计算机又懂管理还要精通统计,同时具有良好的表达和操作能力,这样的人数量稀少,市面上有两类才子:一类是专才,只能独挡一面;一类是通才,夸夸其谈,似乎什么都会,啥都能干。其实,大数据之路,没有捷径,需要吃苦、能够实干。 就先谈这些吧。欢迎大家的批评和建议。
第1章 什么是大数据 “ 大数据”到底是什么?这个概念乍看上去相当模糊,它似乎指的是数量庞大信息量巨大的数据。尽管这样的描述确实符合“大数据”的字面含义,但它并没有解释清楚大数据到底是什么。 大数据常常被描述成已经大到无法用传统的数据处理工具进行管理和分析的极大的数据集。从网上我们可以得到一个被大多数人所认同的观点:当数据集已经发展到相当大的规模,常规的信息技术已无法有效地处理、适应数据集合的增长和演化时,大数据就应运而生了。换言之,数据集规模已大到难以用传统信息技术进行有效的管理,更不用说从中挖掘价值了。具体来说,难题主要在于数据的采集、存储、检索、共享、分析和数据可视化。 关于大数据到底是什么,绝非三言两语就能解释清楚。这个概念经过演变不仅包含了对数据集规模的描述,还包括数据利用的过程。大数据甚至变成了其他商务概念的代名词,如商业智能(Business Intelligence, BI)、数据分析(Analytics)和数据挖掘(Data Mining)。 大数据虽新,可“大数据”却早已存在。虽然海量的数据规模在最近两年内才形成,但大数据的概念却早已在科学界、医学界等组织中萌芽。这些组织对海量数据集进行复杂的分析,并将其运用于药物研制、物理建模及其他研究领域。然而,正是这些渊源为大数据今日的发展奠定了基础。 1.1 数据分析的春天 科学家们对大数据集进行研究和分析后得出一个结论——数据多多益善。也就是说,数据越多,分析越深入,所得的结论就越全面。于是,研究者们开始在分析过程中引入相关数据集、非结构化数据、归档数据和实时数据,而这反过来又催生出我们今日所谓的“大数据”。 在商业领域中,大数据暗藏商机。据IBM公司称,全球每天产生2.5亿亿(2.5×1018)字节的数据,当今世界90%的数据都是近两年产生的。这些数据来源广泛,有的来自收集气候信息的传感器,有的来自社交媒体网站,还有的是网络上传的数字照片和视频、电子商务交易记录,甚至是手机GPS信号等。这些都是大数据的“催化剂”。更重要的是,所有的数据都蕴含内在价值,利用数据分析、算法和其他技术是可以将这些内在价值提炼出来的。 大数据的价值及其重要性已经在一些领域得到了证明。美国国家海洋和大气管理局(NOAA)、美国国家航空航天局(NASA)、部分制药公司和许多能源公司正在把大数据技术运用于日常工作并从海量的数据中提取价值。 美国国家海洋和大气管理局运用大数据的方法助力气候、生态系统、天气和商业研究,美国国家航空航天局则使用大数据从事航空航天等研究。在大数据的帮助下,制药公司和能源公司已经在药物测试和地理分析方面得到了实际的效益。《纽约时报》利用大数据工具进行文本分析和Web挖掘;迪士尼公司则分析了旗下所有店铺、主题公园和网站的数据,试图发现数据间的关联性,进而理解用户行为。 在如今的商业活动中,大数据还扮演着其他的角色,大型企业越来越迫切地需要维护海量的结构化和非结构化数据——从数据仓库中的交易信息到员工的微博数据,从供应商的供货记录到政府的监管信息(为了符合政府法规的规定)。在近期诉讼案件的审理过程中,法庭鼓励公司保存大量文档、电子邮件以及其他电子通信消息(例如即时消息、网络通话等)。一旦公司面临诉讼,便可以从这些信息中进行电子取证,这也进一步推动了数据维护的需求。 1.2 价值何在 发掘价值从来都是说起来容易做起来难。面对技术、理论、实践中的种种挑战,大数据的发展可谓一路荆棘。任何一种挑战都可能消弭发掘大数据商业价值的能力,进而影响大数据的发展。 对大数据的概念的探究虽然涉及多个维度,不过人们认为以下4个维度最为重要,并将其统称为4V。 1.海量性(Volume)。大数据都是数量巨大的数据。很多企业都拥有海量数据,数据量很容易就积累到TB(1012字节)级,甚至跃升至PB(1015字节)级。 2.多样性(Variety)。大数据冲破结构化数据的局限,不仅包括结构化数据,还覆盖了如文本、音频、视频、点击流[①]、日志文件等各种类型的非结构化数据。 3.精确性(Veracity)。数据量多不见得都是好事,庞杂的数据可能会导致对收集到的信息的误读或统计误差,因此信息的纯度对价值发掘至关重要。 4.时效性(Velocity)。大数据对时效性要求很高,企业必须能够在短时间内高速、流畅地处理源源不断产生或流入企业的海量数据,方能最大化地显现出大数据的商业价值。与此同时,大数据还应被归档存储,以备不时之需。 大数据的4V特征为我们进行数据分析指明了方向,其中每个V在发掘大数据价值的过程中都有着内在价值。然而,大数据的复杂性并非只体现在这4个维度上,还有其他因素在起作用,这些因素存在于大数据所推动的一系列过程中。在这一系列过程中,需要结合不同的技术和分析方法才能充分揭示数据源的价值,进而用数据指导行为,促进业务的发展。 以下诸多支撑大数据的技术或概念早已有之,但现在已归至大数据范畴之下,包含如下方面。 传统商业智能(Traditional Business Intelligence, BI)。商业智能涵盖了多种数据采集、存储、分析、访问的技术及应用。传统的商业智能对来自数据库、应用程序和其他可访问数据源提供的详细商业数据进行深度分析,通过运用基于事实的决策支持系统,给用户提供可操作性的建议,辅助企业用户做出更好的商业决策。在某些领域中,商业智能不仅能够提供历史和实时视图,还可以支持企业预测未来的蓝图。 Data Mining, DM)。数据挖掘是人们对数据进行多角度的分析并从中提炼有价值的信息的过程。数据挖掘的对象通常是静态数据和归档数据,数据挖掘技术侧重于数据建模以及知识发现,其目的通常是预测趋势而绝非纯粹为了描述现状——这是从大数据集中发现新模式的理想过程。 统计应用 (Statistical Application)。统计应用通常是基于统计学原理利用算法来处理数据,一般用于民意调查、人口普查以及其他统计数据集。为了更好地估计、测试或预测分析,可以使用统计软件分析收集到的样本观测值来推断总体特征。调查问卷和实验报告这类经验数据都是用于数据分析的主要数据来源。 预测分析 (Predictive Analysis)。预测分析是统计应用的一个分支,人们基于从各个数据库得到的发展趋势及其他相关信息,分析数据集进行预测。预测分析在金融和科学领域显得尤为重要,因为加入对外部影响因素的分析,更容易形成高质量的预测结论。预测分析的一个主要目标是为业务流程、市场销售和生产制造等规避风险并寻求机遇。 数据建模 (Data Modeling)。数据建模是分析方法论概念的应用之一,运用算法可在不同的数据集中分析不同的假设情境。理想的情况下,对不同信息集的建模运算算法将产生不同的模型结果,进而揭示出数据集的变化以及这些变化会产生怎样的影响。数据建模与数据可视化密不可分,二者结合所揭示的信息能够为企业的某些特定商业活动提供帮助。 上述分析种类仅是大数据的一隅而已,未能展现大数据对商业的全部价值。对利益无尽的追求及不懈的竞争刺激着人们对大数据商业价值的渴求,促使组织机构利用企业内部和外部数据“仓库”中的数据来揭示发展规律、进行数据统计、获取竞争情报,协助他们部署下一步战略。大数据正是企业所需的大“仓库”。这使得大数据及其相关处理工具、平台、分析技术等在企业技术层和管理层中备受青睐。 1.3 琳琅满目的大数据 超大的数据量只是大数据概念的一个部分。人们渐渐形成共识,结构化和非结构化的数据均蕴藏着关键的商业信息,因此必须将这些数据融入商业智能和实际运营之中。另一方面,非结构化的业务数据量不仅现在在增长,在可预见的未来仍将持续增长,而且这一增长趋势非常明显。 大数据涉及结构化数据、半结构化数据和非结构化数据这三类数据。 结构化数据通常指的是传统数据库(SQL或其他数据库)中的数据,这些数据根据预先定义好的业务规则(Business Rule)存储于不同的表中。在数据库中存储数据前需要事先定义数据并创建索引,这使得访问和过滤数据变得非常简单,因此结构化数据最容易处理。 相比之下,非结构化数据一般无法直接进行商业智能分析,这是由于非结构化数据无法直接存储到数据库表中,也无法被程序直接使用或使用数据库进行分析。二进制图片文件就是非结构化数据的一个典型例子。 半结构化数据介于结构化数据和非结构化数据之间。半结构化数据因不具有严格的结构而不同于基于数据库表和关系的结构化数据。半结构化数据也不同于非结构化数据,它使用标签和各种标识区分不同的元素,并提供了记录和字段的层级结构来定义数据。 1.4 不同的数据,统一的处理 得益于标准XML语言格式和行业XML数据标准的应用(如保险行业的ACORD标准[②],医疗行业的HL 7[③]标准),不同类型的数据处理方法日渐趋同。虽然XML技术拓展了大数据分析和集成工具所能处理的数据类型,但是受限于数据的复杂结构及巨量规模,现有工具的转化能力无法满足不断增多的数据处理需求,从而加剧了有限处理能力与新兴需求之间的矛盾。人们急需一种新的通用数据转换工具以应对所有类型的数据(结构化、半结构化、非结构化),不用编写代码就能部署在任何应用软件或平台架构上。 对大数据的认识和分析依旧存在争论,与之相关的工具、技术和过程仍在不断发展。但是,这并不意味着想从大数据中探究价值的人们除了等待别无他法。大数据对商业活动的意义非常大,我们绝不能无所作为。 想要更好地实现数据分析的目标绝非易事,大数据发展的瓶颈在于满足分析需求的同时找到不同数据源的最优处理方法。如此看来,将硬件、软件及处理流程整合成一套可用、易用的管理程序来及时生成分析结论,似乎是明智之举。追根溯源,这一切正是得益于数据。 存储问题对大数据而言至关重要,因为数据必须存储在便于访问和维护之处。由于购买和管理SAN或NAS这样基于网络的存储系统相当昂贵,这一挑战对于很多公司来说代价不菲。 毕竟存储技术早已成熟并且成功商用,存储设备已经成为标准数据中心的常规配备。尽管如此,这仍然无法满足企业对多种存储技术新生的需求。重要的是,随着大数据分析的推进,企业方能利用BI对大数据集进行处理。 对于大数据分析过程所需的处理能力而言,常规的存储模式常常无能为力。诸如SANS、NAS和其他传统的存储技术,无法应对大数据与生俱来的那些动辄TB甚至PB级的非结构化信息。大数据分析若想成功,就需要更多突破:一种全新的海量数据处理方法,以及一个全新的存储平台理念。 1.5 一款开源利器 Hadoop是一个开源项目,它提供了处理大数据的平台。尽管Hadoop已经存在多年,但是越来越多的企业现在才刚刚开始领略到它的威力。Hadoop平台旨在解决海量数据所产生的问题,尤其是混杂有结构化或非结构化的复杂数据问题,因为这些数据无法有效地存储在表中。在类似聚类分析和定位分析这样的场景中,需要深度分析和大量计算进行支撑方能得以处理,而这恰是Hadoop的长处所在。 Hadoop可对海量数据进行有效的序化和访问,从而解决了绝大多数与大数据相关的常见问题,为想要利用大数据的决策者清除了障碍。 Hadoop设计的初衷就是允许数量众多的机器组成一个平台而共同协作,却不必共享任何内存或磁盘。考虑到这一特点,Hadoop怎样带来附加价值便一目了然:网络管理员只需要购置大批商用服务器并安置到机架上,分别运行Hadoop软件即可。 更何况,Hadoop有助于简化大型数据集的繁杂管理。实际操作中,一旦某一组织的数据被载入Hadoop平台,软件就会把数据切分成容易操作的小数据集,然后将其自动分发给不同服务器。由于分布式技术的一个本质特征就是弃用了对数据进行访问的统一入口,那么对于Hadoop中的分布式数据而言,这也就意味着人们可以使用Hadoop从多个地方访问同一数据。而且,Hadoop还跟踪记录数据驻留的位置,并且通过创建多个存储副本来保护数据。该设计增强了系统整体的健壮性,因为即使某个服务器脱机或者宕掉,数据仍可以从一个已知保存完好的副本中自行恢复。 不同于传统数据库系统,Hadoop对数据的深入处理并非一蹴而就。传统集中式的数据库系统固有的局限性,如挂入服务器级系统上的大量硬盘及多个处理器,使得数据分析不但受限于磁盘性能,更取决于其所拥有处理器的数量。 而在Hadoop集群中,Hadoop把任务和数据分发至各个服务器,然后利用这些服务器来进行计算。具体而言,一项任务被分解为一系列作业后,Hadoop将这些作业分发给集群中的每台服务器,服务器分别处理各自的数据分片后,再将所有结果作为统一的整体返回。Hadoop的这个过程被称为“映射-化简”(MapReduce),即指令或作业被映射至所有服务器,而运算结果被化简为单个数据集的过程。 正因为Hadoop能够分发数据并利用所有可用的集群处理器并行工作来解决复杂计算的问题,因此对海量数据的处理成了Hadoop的拿手好戏。 1.6 入门容易修行难 然而,一旦在尝试着步入Hadoop的世界后,你就会发现Hadoop的使用并不是即插即用那么简单的事情,因为除了要满足一定的前提条件以外,硬件配置和系统设置是成功的必备条件。 首当其冲的是理解和定义分析的过程。由于数据的抽取(extract)、转换(transform)和加载(load)在构建BA(业务分析)或BI(商业智能)解决方案中起到关键作用,所以人们将其合称为ETL。所幸,大多数CIO(首席信息官)不仅对BA和BI的过程较为熟悉,还能够把最常用的ETL层和这个过程结合起来。因此,要进行大数据分析之前,企业首先需要挑选并确定哪些数据用来分析,然后对数据进行检验、对比和汇总,最后进行数据整合(ETL)。整个过程同时伴有数量庞大的数据,这些数据来源广泛(社交网络、数据日志、网站、移动设备、传感器和其他领域)并且类型复杂(结构化、非结构化)。 Hadoop基于容错性集群架构,拥有更强的数据计算能力,能够对大数据进行并行或批量处理,还具有一套从数据存储到分析的开放生态圈。不仅该生态圈能够对企业构架进行全方位的支持,Hadoop上述这些特点更有助于支持企业进行大数据分析。 当然,并非所有的企业都需要大数据分析的支持。对于那些确实需要的企业来说,应该考虑利用Hadoop的能力来满足企业需求。不过Hadoop本身并非万能药。在构建Hadoop项目时,企业还必须根据实际需求确定需要用到哪些额外的Hadoop组件。 例如,从软件上看,Hadoop组件虽多,但让其运行起来却只需少数组件构成的组件集合即可。这些组件有:用于数据管理的HDFS和HBase[④],作为任务处理框架的MapReduce或OOZIE,用以提高开发人员开发效率的开发框架Pig和Hive,以及用于BI的开源项目Pentaho。从硬件的角度看,一个测试项目并不需要大量设备。硬件需求可以简单到仅仅两台拥有多核CPU、至少24 GB内存、十几个TB硬盘的服务器即可。事实证明,这样的硬件配置对于一个测试项目的运行而言,已然足够。 需要对数据管理者在观念上打个“预防针”:有效管理和使用Hadoop不能离开专业知识和经验。若真缺乏,信息技术管理部门则应该考虑与服务提供商进行合作,他们可对Hadoop项目提供鼎力支持。此外,这些专业知识对于安全而言,尤为重要。由于Hadoop、HDFS和HBase中默认集成的安全性组件数量极少,所以为了防止数据遭到破坏或窃取,企业仍然需要对数据进行安全保护。 在全面评估之后,企业应该组建一个内部Hadoop项目来对大数据分析的能力进行初步测试。如果初测结果理想,企业还希望更加深入地了解大数据分析,那么已有大量现成的商业和(或)托管解决方案可供选择。 ① 点击流(Click Stream),即指记录用户在Web服务器上的浏览历史。通过分析用户造访页面的历史数据,可以发现用户访问网站的路径、瓶颈、热点连接等,并根据这些数据对系统功能进行相应调整。因此,点击流有时也被称为用户访问路径分析。——译者注 [②] ACORD Transactional/Business Wrapper (TXLife) XML 规范日渐成为寿险、养老金和健康保险行业内用于内部和外部数据集成的首选数据格式。——译者注 [③] HL 7(Health Level Severn),健康信息交换第七层协议。HL 7标准是医疗领域不同应用系统之间电子数据传输的协议,主要目的是要发展各型医疗信息系统间,如临床、检验、保险、管理及行政等各项电子资料交换的标准;主要应用在医疗保健领域,特别是在住院患者急需的医护设施领域内进行及时的电子数据交换。——译者注 [④] HBase(Hadoop Database)是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HDFS作为其文件存储系统。——译者注
IT圈内一直流传着这样一个说法,干技术的到了30岁便需要转型,如果30大几了其身影依旧在活跃在技术第一线不是特成功就是特失败。即使对于一个没有远大志向的程序员来说,年龄也是无法回避的问题。那么,如何在IT职场上进一步求得发展呢,《从技术走向管理——李元芳履职记》对这个问题进行了初步的回答。 我自己也是靠技术起家,遥想当年苦战代码,日夜通宵,双眼惺忪,说实在的真是累;再看现在,年岁不饶人,再让我像年轻时候连续奋战非得吐血了不行。我干过管理层,虽然成绩不错,但说实话这里面还是有很多门道的。一开始我并没有很快地融入到这个身份中,而且我认为这就是一个化蝶的过程,需要完成多个方面的转变。 首先是业务活动的变化。作为领导,你不再是一线员工,即便你有再好的点子、再好的算法、再简洁的思路、可以写出再安全的代码,你都不应该直接编程了。这是由工作性质决定的,你可以为下属指引方向,但不需要事无巨细地亲自上手,因为等待你的有更重要的任务,这个重要的任务具有全局性。 紧接着是表达方式和沟通技巧的变化。作为下属员工,顺便说说、天南海北地扯闲都行;但是作为上级领导,就不能再如此不管好自己的嘴了。此时,你负责的不再只有你一个人,而是你和你手下以及你要负责的你的领导这样的一个利益共同体,权利与责任背靠背,协调项目进度及人际沟通是你的主业。 最后是心态的转变。这是需要修炼的,也是最难的。作为领导,必然肩负着更大的责任,与之俱来的是更大的压力,这些压力看不见、摸不着,很多时候你只能自己咬牙受着,此时若是冲动往往招致不利。所以,对自己的管教才是最难的,管理自己比管理别人难度更大。 本书以故事的方式为大家娓娓道来这些经验,作者是过来人写的重点分明。当然这是指样章的节选,希望全书能够为菜鸟领导的事业进步提供更多更全面更有价值的“干货”以馈读者。 最后一句引用彼得德鲁克的经典名言作为结束:某些管理者有个常犯的毛病,即专家式的傲慢。认为别人都应该懂得他们的术语,并按照他的方式来思维。……他们认为其余的人即使不沟通,也应该知道做什么。所以,卓有成效的管理者不禁要问:“自己应该贡献什么?”而且也要问:“在公司里谁应该知道我想要贡献什么,以及我正在做什么?我该用什么方式表达,才能让别人理解和运用,是别人也成为卓有成效的管理者?”。
做了多年的B/S开发,遇到过数不胜数的浏览器兼容问题,采用过N多JavaScript脚本以及CSS代码为应用程序打补丁。为什么我们会对HTML5这么推崇,因为做过前端开发的都知道。书中说道,现在使用最广泛的HTML4标准已经十余年没有重要更新,对于构建复杂的网页应用也越来越显得力不从心。 HTML5不是终极武器,而是改良利刃。前向兼容的同时又增加了许多新特性,尤其是在移动互联网方面力度更大。市面上HTML5书籍不少,入门书所占比例较大,很多知识讲解的比较粗略,缺少的就是本书这类详细阐述的书籍。 那么本书能为读者带来什么呢?从结构上看,本书回答了三个问题:一是为什么选用HTML5,它由那些改进与革新;二是HTML5标准的主要应用,语义与结构、表单、多媒体处理、CSS3、Canvas绘图及HTML5的API;三是与HTML5相关的新技术,比如响应式设计、离线应用缓存、微数据等等。这些内容已经覆盖了学习HTML5的主要方面,翻看样章可以感受到作者不仅要告诉人们应该做什么,还试图说明为什么要这么做,这一点难能可贵。再加上后文应用性的实战性介绍,应该可以让学习HTML5的前端工程师们轻松地迈过这个门槛。 HTML5是目前移动开发的热门之一,IOS与Android平台都有许多HTML5应用。学习本书应该与HTML5开发框架结合,目前较为知名的HTML5框架有:LungoJS、Kendo UI、Sencha Touch、Jo、52 Framework、LimeJS等。另外一个重要应用领域--游戏,现今也有EntityJS、QuarkJS、Gamvas Web、X-Canvas等开发框架,而且诸如LungoJS和LimeJS也是游戏开发框架的上乘之选。 路漫漫而修远兮,吾将上下而求索。但愿这本《深入理解HTML5:语义、标准与样式》可以陪伴前端工程师走向更远的将来。
世界上已经成型的爬虫软件多达上百种,本文对较为知名及常见的开源爬虫软件进行梳理,按开发语言进行汇总,如下表所示。虽然搜索引擎也有爬虫,但本次我汇总的只是爬虫软件,而非大型、复杂的搜索引擎,因为很多兄弟只是想爬取数据,而非运营一个搜索引擎。 开源爬虫汇总表 开发语言 软件名称 软件介绍 许可证 Java Arachnid 微型爬虫框架,含有一个小型HTML解析器 GPL crawlzilla 安装简易,拥有中文分词功能 Apache2 Ex-Crawler 由守护进程执行,使用数据库存储网页信息 GPLv3 Heritrix 严格遵照robots文件的排除指示和META robots标签 LGPL heyDr 轻量级开源多线程垂直检索爬虫框架 GPLv3 ItSucks 提供swing GUI操作界面 不详 jcrawl 轻量、性能优良,可以从网页抓取各种类型的文件 Apache JSpider 功能强大,容易扩展 LGPL Leopdo 包括全文和分类垂直搜索,以及分词系统 Apache MetaSeeker 网页抓取、信息提取、数据抽取工具包,操作简单 不详 Playfish 通过XML配置文件实现高度可定制性与可扩展性 MIT Spiderman 灵活、扩展性强,微内核+插件式架构,通过简单的配置就可以完成数据抓取,无需编写一句代码 Apache webmagic 功能覆盖整个爬虫生命周期,使用Xpath和正则表达式进行链接和内容的提取 Apache Web-Harvest 运用XSLT、XQuery、正则表达式等技术来实现对Text或XML的操作,具有可视化的界面 BSD WebSPHINX 由两部分组成:爬虫工作平台和WebSPHINX类包 Apache YaCy 基于P2P的分布式Web搜索引擎 GPL Python QuickRecon 具有查找子域名名称、收集电子邮件地址并寻找人际关系等功能 GPLv3 PyRailgun 简洁、轻量、高效的网页抓取框架 MIT Scrapy 基于Twisted的异步处理框架,文档齐全 BSD C++ hispider 支持多机分布式下载, 支持网站定向下载 BSD larbin 高性能的爬虫软件,只负责抓取不负责解析 GPL Methabot 经过速度优化、可抓取WEB、FTP及本地文件系统 不详 Methanol 模块化、可定制的网页爬虫,速度快 不详 C# NWebCrawler 统计信息、执行过程可视化 GPLv2 Sinawler 国内第一个针对微博数据的爬虫程序,功能强大 GPLv3 spidernet 以递归树为模型的多线程web爬虫程序,支持以GBK (gb2312)和utf8编码的资源,使用sqlite存储数据 MIT Web Crawler 多线程,支持抓取PDF/DOC/EXCEL等文档来源 LGPL 网络矿工 功能丰富,毫不逊色于商业软件 BSD PHP OpenWebSpider 开源多线程网络爬虫,有许多有趣的功能 不详 PhpDig 适用于专业化强、层次更深的个性化搜索引擎 GPL Snoopy 具有采集网页内容、提交表单功能 GPL ThinkUp 采集推特、脸谱等社交网络数据的社会媒体视角引擎,可进行交互分析并将结果以可视化形式展现 GPL 微购 可采集淘宝、京东、当当等300多家电子商务数据 GPL ErLang Ebot 可伸缩的分布式网页爬虫 GPLv3 Ruby Spidr 可将一个或多个网站、某个链接完全抓取到本地 MIT 五岳之巅原创,转载请注明出处。
续前文:《数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置》。 程序优化:第一步开始: for i in range(startx,total): for j in range(starty,total): BASE_URL = createTheUrl([item[i],item[j]]) driver.get(BASE_URL) driver = webdriver.PhantomJS() html = driver.page_source output = filterOutcome(html) driver.quit() print 'i='+str(i)+'tj='+str(j)+'tresult='+str(output) j += 1 每个耗时约27秒。修改后: driver = webdriver.PhantomJS() for i in range(startx,total): for j in range(starty,total): BASE_URL = createTheUrl([item[i],item[j]]) driver.get(BASE_URL) html = driver.page_source output = filterOutcome(html) print 'i='+str(i)+'tj='+str(j)+'tresult='+str(output) if output == -1: driver.quit() exit(0) j += 1 driver.quit() 这回只分析了3个,共52秒,每个耗时约17秒,只是因为避免了重复PhantomJS的开启、运行和关闭这一过程。程序优化:第二步 减少对角线重复请求次数: driver = webdriver.PhantomJS() for i in range(startx,total): if starty != -1: k = i else: k = starty for j in range(k,total): BASE_URL = createTheUrl([item[i],item[j]]) driver.get(BASE_URL) html = driver.page_source output = filterOutcome(html) print 'i='+str(i)+'tj='+str(j)+'tresult='+str(output) if output == -1: driver.quit() exit(0) #toexcel("C:catchoutput.xlsx","Sheet1",output,i,j) j += 1 driver.quit() 和上面的待分析的个数一样,花费21秒,每个耗时约7秒。如果开启excel存储,则共花费25秒,每个耗时约8秒。程序优化:第三步 减少写入Excel的次数,提高硬盘性能。当然,数据量越大,次数越多,效果越明显。这次把Excel一直打开,每隔20个保存一次。 #打开Excel插件 xlsApp = win32com.client.Dispatch("Excel.Application") xlsBook = xlsApp.Workbooks.Open('C:catchoutput.xlsx') xlsSheet = xlsBook.Sheets('Sheet1') #开启webdirver的PhantomJS对象 driver = webdriver.PhantomJS() #main()for i in range(startx,total): if starty != -1: k = i else: k = starty for j in range(k,total): BASE_URL = createTheUrl([item[i],item[j]]) driver.get(BASE_URL) html = driver.page_source output = filterOutcome(html) print 'i='+str(i)+'tj='+str(j)+'tresult='+str(output) mycounter += 1 if output == -1: driver.quit() xlsBook.Save() xlsBook.Close() xlsApp.Quit() exit(0) xlsSheet.Cells(j+1,i+1).Value = xlsSheet.Cells(i+1,j+1).Value = output #每隔20个保存一次,并重新清零 if mycounter%20 == 0: print "~~~~~~ SAVED HERE ~~~~~~" xlsBook.Save() mycounter = 0 j += 1 #程序结束前的清扫工作 driver.quit() xlsBook.Save() xlsBook.Close() xlsApp.Quit() 结果如下: >>> 请输入起始XaaS的序号X:0 请输入起始XaaS的序号Y:0 待处理数据记录总数:8 条 待处理握手总数:36 次 读取info.txt文件成功 计时开始! ---------------- i=0 j=0 result=14000000 i=0 j=1 result=2 i=0 j=2 result=8 i=0 j=3 result=1 i=0 j=4 result=80400 i=0 j=5 result=2 i=0 j=6 result=3 i=0 j=7 result=8470 i=1 j=1 result=394000 i=1 j=2 result=3140 i=1 j=3 result=9 i=1 j=4 result=57 i=1 j=5 result=7 i=1 j=6 result=3790 i=1 j=7 result=718 i=2 j=2 result=7110000 i=2 j=3 result=7 i=2 j=4 result=4 i=2 j=5 result=232000 i=2 j=6 result=382000 i=2 j=7 result=7970 i=3 j=3 result=981000 i=3 j=4 result=7 i=3 j=5 result=1 i=3 j=6 result=2 i=3 j=7 result=10 i=4 j=4 result=398000 i=4 j=5 result=4 i=4 j=6 result=3850 i=4 j=7 result=1390 i=5 j=5 result=275000 i=5 j=6 result=32100 i=5 j=7 result=8 i=6 j=6 result=8050000 i=6 j=7 result=67800 i=7 j=7 result=738000 ---------------- 执行成功! 程序耗时:72 秒 相当于每次握手,花费2秒。但这还存在一个致命伤,那就是在随着数据量的激增,以后经常要保存上万个值,每次都保存,那么次数越多写入量就会越大。只是希望微软的Excel已经能够知道:哪些是未改动数据就不必再次写入,哪些数据改动过需要写入。程序优化:第四步 使用多线程+使用数据库。如果不用数据库,就靠读写一个单机版的Excel,效率太低,因此我考虑用Mysql或Sqlite。最后再将结果转出来。 也请参看下文: 《数据抓取的艺术(三):抓取Google数据之心得》
mechanize是对urllib2的部分功能的替换,能够更好的模拟浏览器行为,在web访问控制方面做得更全面。结合beautifulsoup和re模块,可以有效的解析web页面,我比较喜欢这种方法。 下面主要总结了使用mechanize模拟浏览器的行为和几个例子(谷歌搜索,百度搜索和人人网登录等) 1.初始化并建立一个浏览器对象 如果没有mechanize需要easy_install安装,以下代码建立浏览器对象并作了一些初始化设置,实际使用过程可以按需开关。其实只用默认的设置也可以完成基本任务。 #!/usr/bin/env python import sys,mechanize #Browser br = mechanize.Browser() #options br.set_handle_equiv(True) br.set_handle_gzip(True) br.set_handle_redirect(True) br.set_handle_referer(True) br.set_handle_robots(False) #Follows refresh 0 but not hangs on refresh > 0 br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) #debugging? br.set_debug_http(True) br.set_debug_redirects(True) br.set_debug_responses(True) #User-Agent (this is cheating, ok?) br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')] 2.模拟浏览器行为 浏览器对象建立并初始化完毕之后即可使用了,下面给出几个例子(代码承接以上部分) 获取web网页 分行打印可以逐个查看详细信息,就不赘述 r = br.open(sys.argv[1]) html = r.read() print html print br.response().read() print br.title() print r.info() 模拟谷歌和百度查询 打印和选择forms,然后填写相应键值,通过post提交完成操作 for f in br.forms(): print f br.select_form(nr=0) 谷歌查询football br.form['q'] = 'football' br.submit() print br.response().read() 百度查询football br.form['wd'] = 'football' br.submit() print br.response().read() 相应键值名,可以通过打印查出 回退(Back) 非常简单的操作,打印url即可验证是否回退 # Back br.back()print br.geturl() 3.http基本认证 br.add_password('http://xxx.com', 'username', 'password') br.open('http://xxx.com') 4.form认证 以登陆人人网为例,打印forms可以查出用户名和密码键信息 br.select_form(nr = 0) br['email'] = username br['password'] = password resp = self.br.submit() 5.cookie支持 通过导入cookielib模块,并设置浏览器cookie,可以在需要认证的网络行为之后不用重复认证登陆。通过保存session cookie即可重新访问,Cookie Jar完成了该功能。 #!/usr/bin/env python import mechanize, cookielib br = mechanize.Browser() cj = cookielib.LWPCookieJar() br.set_cookiejar() 6.proxy设置 设置http代理 #Proxy br.set_proxies({"http":"proxy.com:8888"}) br.add_proxy_password("username", "password") #Proxy and usrer/password br.set_proxies({"http":"username:password@proxy.com:8888"})
《合作的进化》读后感 感谢段钊老师的推荐,趁着五一国假我读完了《合作的进化》[1]。本书的作者是美国人罗伯特·阿克塞尔罗德,此人最早是一名政治学家,后因研究合作进化问题成名,参与过许多重要的国际政治经济合作事务,并见证了东西方冷战与苏联解体。 然而,合作不只是政治问题,更是可以牵涉到个人利益的经济问题,甚至有时还是一个生死存亡的生存问题。所幸的是,阿克塞尔罗德与生物化学家W·D·汉密尔顿进行合作,将研究结论从人类社会推广到整个生物世界中。一时间,掀起一股研究合作进化的热潮来。各种时髦新词应运而生,诸如:合作的进化、演进合作、演化博弈论等等不一而足。 那么究竟是一个什么样的结论让各国人民都如此兴奋呢? 一切都源于一个计算机程序模拟比赛。1980年左右,阿克塞尔罗德教授设计了一次计算机程序对决赛,参赛的14个程序来自心理学、经济学、政治学、数学和社会学等5个学科。之所以如此选择,是因为他知道这些学科中的学者熟悉博弈论,所以精心挑选了某些他认为既懂博弈论又能写程序的人,并向这些人发出邀请。 在囚徒困境情景下,14个程序轮流循环对决,为了严谨起见还加入了一个随机“合作或背叛”的程序。最后结果令人惊讶,最简单的“一报还一报”赢得了比赛。不仅如此,若干年后阿克塞尔罗德教授将结果公布出来,又进行了第二次征集。这次有更多国家更多程序参赛,不过获胜的依旧是“一报还一报”策略。 从中可以看出,有关“重复囚徒困境”的计算机程序比赛得出了极有意思的结果:合作,绝不是那种“打左脸,把右脸也转过去给他”的善良,而是“人不犯我,我不犯人;人若犯我,我必犯人”的实践。被淘汰的策略不仅仅包括了总是背叛的“小人”策略,还包括了总是合作从不背叛从而被“小人”占尽便宜的“善人”策略、一旦被背叛就永远不再合作的“记仇”策略、完全随机背叛或合作的“任性”策略、过分复杂的“老谋深算”策略……[2] 随后阿克塞尔罗德教授进行了深入分析认为:合作的基础不是真正的信任,而是合作关系的持续性。在有限次短暂的相处中,最优策略一定存在,那就是全部都背叛。这就意味着,如果人们只是萍水相逢,不管对方是否合作,自己选择不合作才是最好的。但是在无限次长期的相处中,虽然没有绝对的最优策略,但在某些条件下,合作才是最优解。当然合作也有很多类型,有主动献媚的,有倾向防御的,有冤大头的,也有机警的。其中只有一种在两次不同的比赛中都却得了第一:一报还一报型。 为什么“一报还一报”能有如此优异的表现呢? 因为一报还一报具有如下天生的特质:①善良,一开始与别人相处,它摆出合作的姿态,愿意主动示好以争取进一步合作的机会;②报复,一味的示好就是软弱,只会成为大头而被他人占尽便宜。在存在竞争的场合,软弱就会失败。而一报还一报就不好欺负,一旦吃亏一定让对方也付出代价;③宽容,小偷的儿子未必是小偷,犯过错的人未必还会犯错,普天之下谁能无错?给他人一个改正的机会,有时是更好合作的必要。一报还一报就是这样,你若不犯我,我定不犯你;④清晰,正常智商的人们遇到一报还一报型的对手都能很快明白该如何与之相处,不像有些策略时而看似简单时而看似悬密,让人摸不清参不透,最后伤了别人也害了自己。也许“一报还一报”策略并不完美,但它绝对实用。 那么什么样的条件下,合作而非背叛才会自然胜出呢? 这个问题可以被书中称为“初始成活性”、“鲁棒性”和“稳定性”问题来回答。 “初始成活性”回答的是,合作在一个广泛不合作的环境里是如何产生的。阿克塞尔罗德教授认为一个合作取向的行为策略可以通过有意的分析、试错或仅仅是幸运而出现。而合作的出现,只需要两个都能采取合作策略的个体相遇即可。遗憾的是,事实上培育合作并不是如此简单,在一个淫恶的“恶棍世界”中,单独的合作个体无法立足,只会被湮灭。不过哪里有失望,哪里就有希望。只要这样的“好”个体数量达到一定程度,不必太大5%足矣,“好人”便可以在“恶棍”圈子里混迹并慢慢感化周围的“坏人”。5%的比例是保证少数采用合作策略的“好人”可以经常见面,利用“好人”之间互的之利对抗他们被“坏人”剥夺之损。 “鲁棒性”,鲁棒是Robust的音译词,表示健壮和强壮之意。它是在异常和危险情况下系统生存的关键指标,即指系统在扰动或不确定的情况下仍能保持自己的特征行为的能力。长期的相互关系是合作策略胜出的必要条件。注意,只要关系是长期的便可,不一定双方非得是朋友,书中例举的二次世界大战中英军与德军在两个战壕中长期对峙,虽说二者是敌人,但“自己活也让别人活”的信念使得敌人之间也产生了彼此的合作,除非上峰下令,否则一般情况下都只是“就某个特定地方进行有规律的开火”。 还有一个问题“已经在持续中的合作又如何能够避免另一方的背叛”,答案就是进行报复。没有能力进行报复,就没有能力保卫自己。有时进攻是最好的防守,有时防守也是最好的进攻。所以说,没有能力进攻的防守,是守不住的。保护合作的可靠手段就是打击“犯罪”。本可以友好相处,对于贪图小利占便宜的人,要能够予以有力的还击,这些人才能收敛、才不敢再次冒犯。 因此,合作可以发展出友情,但最初一定不是友情,所有打着友情的名义谈合作,大多都是骗人的伎俩或是暗伏的陷阱。 那么如何培育合作呢? 阿克塞尔罗德教授简明扼要地给出了回答:不要嫉妒,不要首先背叛,对合作与背叛要予以回应,不要耍小聪明。 此外,本书还介绍了如何促进合作,合作的社会结构以及回报的鲁棒性等。但是就我而言,我十分关心的问题是: 这个结论是否如其所言“广泛成立”? 虽说研究结论对于一切生物界都适用,但研究本身确是有前提的。它的前提是囚徒困境,对于有限次博弈来说,结果很悲观,人们最好采取敌对之势才是上策;对于无限次博弈而言,结果很客观,不论人们采用什么对策,善良的对策总是最后的赢家,而且这种合作可以但不必出现于血缘关系中。问题就是现实世界不只有囚徒困境,还有更多非囚徒困境的困境。囚徒困境只是一个理想化的抽象模型而已,它来自现实但不能回退为现实。现实世界,在合作与背叛间,往往有更多的选择,比如某大国常备的“弃权”。虽然研究的确揭示了合作演进的机理,但此机理是无法直接照搬到生活中的。因为现实太比模型复杂得太多。 这个结论在多大程度上具有推广性? 我觉得虽然结论无法直接施用,但其适用范围却很大,起码在观念上应该明确利益的最大化来自双方合作而非对抗,此谓“双赢”。在谈判时,可以将最终目标分为好几个小段,分段谈,增加交流机会与默契,这也正合了某本推销秘籍中的金玉良言“取胜之道不在一口吞掉狮子”。 不过现实中的人同时也是复杂的,既有合作之趋又有私己之念,人的行为也经常矛盾,常常在现实与理想的矛盾之间徘徊。《白鹿原》中有过这样的描写: “圣人能看透凡人的隐情隐秘,凡人却看不透圣人的作为;凡人和圣人之间有一层永远无法沟通的天然界隔。圣人不屑於理会凡人争多嫌少的七事八事,凡人也难以遵从圣人的至理名言来过自己的日子。圣人的好多广为流传的口歌化的生活哲理,实际上只有圣人自己可以做得到,凡人是根本无法做到的。「房是招牌地是累,按下银钱是催命鬼。」这是圣人姐夫的名言之一,乡间无论贫富的庄稼人都把这句俚语口歌当经念。当某一个财东被土匪抢劫财宝又砍掉了脑袋的消息传开,所有听到这消息的男人和女人就会慨叹着吟诵出圣人的这句话来。人们用自家的亲身经历或是耳闻目睹的许多银钱催命的事例反覆论证圣人的圣言,却没有一个人能真正身体力行。凡人们兴味十足甚至幸灾乐祸一番之後,很快就置自己刚刚说过的血淋淋的事例於脑後,又拚命去劳作去挣钱去迎接催命的鬼去了,在可多买一亩土地再添一座房屋的机运到来的时候绝不错失良机。凡人们绝对信服圣人的圣言而又不真心实意实行,这并不是圣人的悲剧,而是凡人永远成不了圣人的缘故。” 世事无常,如果像作者所说,能够通过增加人与人之间的长久联系来增强合作,同时毋庸置疑的也是这会出现吃大锅饭、坐顺风车的现象。有时人与人之间的利益冲突并不是囚徒困境的小格子就能表述清楚的,大家都是同事,需要长期合作,但一报还一报的合作策略虽然平均最高却总是比对手分低,如果领导只有一人能当。谁想通过合作来培养他人成功?如何能改变这些人的囚徒困境收益值?如何能通过教育自己让他人成为领导,或者如何教育他人让自己成为领导?除非这个人没有下进心,也没有上进心。 所以,在我看来,有得必有失。如果说上天最大,那么上天安排的这个规则便比公平还公平。在这个游戏规则下,没有成王也没有败寇,有的只是选择。也许这就是人生,虽然它需要与人合作,但我坚信它也需要与人不合作。 是以为感,成以为文。 刘 凯 2013-5-6,于桂子山 [1] 罗伯特·阿克塞尔罗德.合作的进化[M].上海:上海世纪出版集团,2007(8). [2] http://book.douban.com/review/1421768/.
1、最简单 import urllib.requestresponse = urllib.request.urlopen('http://python.org/')html = response.read() 2、使用 Request import urllib.requestreq = urllib.request.Request('http://python.org/')response = urllib.request.urlopen(req)the_page = response.read() 3、发送数据 #! /usr/bin/env python3 import urllib.parseimport urllib.requesturl = 'http://localhost/login.php'user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'values = {'act' : 'login','login[email]' : 'yzhang@i9i8.com','login[password]' : '123456' }data = urllib.parse.urlencode(values)req = urllib.request.Request(url, data)req.add_header('Referer', 'http://www.python.org/')response = urllib.request.urlopen(req)the_page = response.read()print(the_page.decode("utf8")) 4、发送数据和header #! /usr/bin/env python3 import urllib.parseimport urllib.requesturl = 'http://localhost/login.php'user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'values = {'act' : 'login','login[email]' : 'yzhang@i9i8.com','login[password]' : '123456' }headers = { 'User-Agent' : user_agent }data = urllib.parse.urlencode(values)req = urllib.request.Request(url, data, headers)response = urllib.request.urlopen(req)the_page = response.read()print(the_page.decode("utf8")) 5、http 错误 #! /usr/bin/env python3 import urllib.requestreq = urllib.request.Request('http://www.python.org/fish.html')try: urllib.request.urlopen(req)except urllib.error.HTTPError as e:print(e.code)print(e.read().decode("utf8")) 6、异常处理1 #! /usr/bin/env python3 from urllib.request import Request, urlopenfrom urllib.error import URLError, HTTPErrorreq = Request("http://twitter.com/")try: response = urlopen(req)except HTTPError as e:print('The server couldn\'t fulfill the request.')print('Error code: ', e.code)except URLError as e:print('We failed to reach a server.')print('Reason: ', e.reason)else:print("good!")print(response.read().decode("utf8")) 7、异常处理2 #! /usr/bin/env python3 from urllib.request import Request, urlopenfrom urllib.error import URLErrorreq = Request("http://twitter.com/")try: response = urlopen(req)except URLError as e:if hasattr(e, 'reason'):print('We failed to reach a server.')print('Reason: ', e.reason)elif hasattr(e, 'code'):print('The server couldn\'t fulfill the request.')print('Error code: ', e.code)else:print("good!")print(response.read().decode("utf8")) 8、HTTP 认证 #! /usr/bin/env python3 import urllib.request# create a password managerpassword_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()# Add the username and password.# If we knew the realm, we could use it instead of None.top_level_url = "https://cms.tetx.com/"password_mgr.add_password(None, top_level_url, 'yzhang', 'cccddd')handler = urllib.request.HTTPBasicAuthHandler(password_mgr)# create "opener" (OpenerDirector instance)opener = urllib.request.build_opener(handler)# use the opener to fetch a URLa_url = "https://cms.tetx.com/"x = opener.open(a_url)print(x.read())# Install the opener.# Now all calls to urllib.request.urlopen use our opener.urllib.request.install_opener(opener)a = urllib.request.urlopen(a_url).read().decode('utf8')print(a) 9、使用代理 #! /usr/bin/env python3 import urllib.requestproxy_support = urllib.request.ProxyHandler({'sock5': 'localhost:1080'})opener = urllib.request.build_opener(proxy_support)urllib.request.install_opener(opener)a = urllib.request.urlopen("http://g.cn").read().decode("utf8")print(a) 10、超时 #! /usr/bin/env python3 import socketimport urllib.request# timeout in secondstimeout = 2socket.setdefaulttimeout(timeout)# this call to urllib.request.urlopen now uses the default timeout# we have set in the socket modulereq = urllib.request.Request('http://twitter.com/')a = urllib.request.urlopen(req).read()print(a) @see http://docs.python.org/release/3.2/howto/urllib2.html
今天立春了。万物即将复苏,也包括人的心。沉寂的冬叔叔收起严肃的脸庞在悄然退去,温馨的春阿姨面带微笑正迎面走来。 在寒冷的北方、凌冽的北风纵然还要折磨我们几天,不过地下的小生命已经在穿衣服准备起床啦。不喜欢喧嚣的夏,也不喜欢无声的冬,比起蓝调的秋日,我更爱舒展的春天。我爱看软泥中探出的那几点新绿,我爱闻迎春花妆扮的那一抹艳黄,我爱听溪水汩汩拍打浮冰那幽蓝的声音,我爱一个人懒散地躺在山谷中沐浴着暖阳,让那红彤彤的气息将我全身浸润。 我爱春天,爱她的一切,打小就爱,还将永远这般地爱下去。 五岳之巅 2013年2月4日晚7点 于翼城东关
Python文件操作是Python编程的基础,其实不难和C语言很像。内容无非分为几大块: 新建文件/目录 删除文件/目录 使用文件/得到目录 复制/移动文件 判断文件/目录 获得文件信息 此外,还有目录内容列表、路径操作、文件合并操作等。请注意,我使用的版本是3.3。现在言归正传:0、前提 所有后续操作,应该先导入os模块(os是小写),即:import os 1、新建文件/目录 (1)创建文件 第一种方法是使用os模块内置方法mknod创建节点,mkfilo是创建管道。但是3.3版本下,我尝试用它来创建空文件,失败: >>> import os >>> mknod('newfile') Traceback (most recent call last): File "", line 1, in module> mknod('newfile') NameError: name 'mknod' is not defined >>> os.mknod('newfile') Traceback (most recent call last): File "", line 1, in module> os.mknod('newfile') AttributeError: 'module' object has no attribute 'mknod' 我不知道是因为什么原因,在网上查找也没有结果。我将去CU论坛里求助,有了结果会尽快更新博客的。大家要是知道的话,可以直接回复本文。 感谢yk325对我的启发。 第二种方式,比较常用。和C一样,参数都一样: open("test.txt",w),该方法将直接打开一个文件,如果文件不存在则创建文件 关于open 模式: w:写打开 a:追加打开(从 EOF 开始, 必要时创建新文件) r:读打开,如果open("this.txt")这种写法,默认就是r r+:读写打开 w+:读写打开 a+:读写打开 rb、wb、ab:二进制模式 rb+、wb+、ab+:二进制读写模式打开 (2)创建目录 如果知道父目录,只是在其下创建一个子目录的话,容易:>>> os.mkdir(r"C:\Users\lk\Desktop\python\No1") 如果想同时新建多层目录,就需要使用makedirs,比如:>>> os.makedirs(r"C:\Users\lk\Desktop\python\No1\No2\No3\No4") 需要格外注意:mkdir(正确) != mkdirs(错误) != makedirs(正确)2、删除文件/目录 (1)删除文件 删除文件使用的是os.remove(不是move),如下例所示 >>> os.remove(r"C:\Users\lk\Desktop\python\test3.txt") >>> os.remove(r"C:\Users\lk\Desktop\python\No1") Traceback (most recent call last): File "", line 1, in module> os.remove(r"C:\Users\lk\Desktop\python\No1") PermissionError: [WinError 5] 拒绝访问。: 'C:\\Users\\lk\\Desktop\\python\\No1' 使用remove删除文件,不论文件是否为空都可以。但它不能用来删除目录,否则拒绝访问。 (2)删除目录 删除空目录,使用rmdir。当然你肯定不过瘾,怎样全删呢,不管有多少个子目录,里面又含有多少文件,用rmtree搞定。想使用rmtree,它并不在os标准包中,所以还需要shutil包: >>> os.rmdir(r"C:\Users\lk\Desktop\python\No1\No2\No3\No4") >>> import shutil >>> shutil.rmtree(r"C:\Users\lk\Desktop\python\No1") 3、使用文件/进入目录 (1)使用文件 这里使用的意思是读取、写入和追加。 先来看读。是的没错,在家吃冰箱里的冷饮前提是家里首先要有冰箱。读前需要确保文件已经打开,然后使用read()、readline()、readlines()方法即可,区别在于readline()将从当前位置读取一行并以“/n”结尾(麻烦的是很多行末已经是“/n”结尾罗,所以可以预想,将产生很多空行),readlines()接着没读完的读完,负责把剩下的内容全部一次性读出来组成字符串列表返回,而read()则从头到尾整体读出到一个长长的字符串中。 再来看写,写很简单,用write()写入就可以罗。写完了可以close关闭文件,内容便保存起来了。 >>> myfile = open(r"C:\Users\lk\Desktop\python\Test.txt",'w+') >>> myfile.write(""" 五岳之巅 滚雷执闪劈裂天, 怒对风狂山涧间。 脚踩神魔百尺潭, 头举妖仙万韧山。 荆棘塞途奈我何, 断崖绝路又何难? 有朝一日登高处, 万卷浮云任尔翻。 """) 80 >>> myfile.close() >>> myfile = open(r"C:\Users\lk\Desktop\python\Test.txt",'r') >>> myfile.readline() '\n' >>> myfile.readline() '五岳之巅\n' >>> myfile.readlines() ['\n', '滚雷执闪劈裂天,\n', '怒对风狂山涧间。\n', '脚踩神魔百尺潭,\n', '头举妖仙万韧山。\n', '\n', '荆棘塞途奈我何,\n', '断崖绝路又何难?\n', '有朝一日登高处,\n', '万卷浮云任尔翻。\n'] >>> myfile.seek(0,0) 0 >>> myfile.read() '\n五岳之巅\n\n滚雷执闪劈裂天,\n怒对风狂山涧间。\n脚踩神魔百尺潭,\n头举妖仙万韧山。\n\n荆棘塞途奈我何,\n断崖绝路又何难?\n有朝一日登高处,\n万卷浮云任尔翻。\n' 有个想法,要实验一下,如何定位使本诗变为两句一行的形式?我是这样想的,2-3合并,4-5合并,...以此类推。合并要把偶数行尾的“\n”弄掉。现在文件里面是这个样子的: 两种解决方案: 第一种,笨办法,打开文件,每次读一行,遇到2-3/4-5就删一个“\n”: import os f = open(r"C:\Users\lk\Desktop\python\Test.txt",'r') h = open(r"C:\Users\lk\Desktop\python\Result.txt",'w+') #i为行号变量 i = 1 #j为修改类型,1为删除,0为不变 j = [1,1,0,1,0,1,0,0,1,0,1,0,1,0] for i in range(0,len(j)): s = f.readline() if j[i]: s = s[:-1] h.write(s) i = i + 1 f.close() #重新读取j h.seek(0,0) h.read() h.close() 其中,s = s[:-1]这个用法非常好,要不是为了这个,谁会用如此麻烦的方式完成程序?结果如下: 第二种,搜“,”,逗号下一个“\n”删之即可。这个方法很好,简单,高效。哈哈。 import os f = open(r"C:\Users\lk\Desktop\python\Test.txt",'r') h = open(r"C:\Users\lk\Desktop\python\Result.txt",'w+') str = f.read() s = str.split(',') str = s[0][1:] for i in range(1,len(s)): str = str +','+ s[i][1:] i = i + 1 h.write(str) f.close() h.close() 可以看出,这种方法代码不多。 最后还有个追加问题,追加的方法是用open(xxx,'a')来控制,用a打开的文件默认就是seek(2,0)游标处于文件尾。还是举例: import os f = open(r"C:\Users\lk\Desktop\python\Result.txt",'a+') str = "\n作者:五岳之巅,2011年1月14日,13点于榴花\n" f.write(str) f.close() 结果如下图: 最近我在看《数学之美》这本书,我在想对于每一行我们可以使用len(readline())进行测量并统计,不过真实世界中经常是整段统计,是按自然段落统计而非行统计,搜索引擎就是这样,对于不同位置的段还赋予不同的权重,比如第一自然段和最后一自然段权重较高。 我的问题是如何用Python简单地统计一篇文章段落的词数? 要解决的关键问题就只有一个,即“什么是段落?”答:必须满足连续文字前后两个“\n”之间的就是段落。于是我写了如下的代码,也赶了个时髦,统计莫言《蛙》的第一部第一章的自然段,并输出统计内容。原文如下: 使用如下代码: import os f = open(r"C:\Users\lk\Desktop\python\wa.txt",'r') #r保存结果 r = {} paper = (f.read()).split('\n\n') num = 1 for i in paper: r[num] = len(i) num = num + 1 f.close() #range(1,num)是不包含num的 for key in range(1,num): print("第%s自然段:共有%d个字\n"%(key,r[key])) 得到如下结果: >>> 第1自然段:共有250个字 第2自然段:共有130个字 第3自然段:共有2566个字 第4自然段:共有409个字 第5自然段:共有87个字 好了,到这里已经做出了一个简易的段落字数统计,下一步还可以深入做下去,比如我想知道这一章主要讲的什么,怎么办?没错,那就得分析词频了,最近看到一款“结巴分词”软件,是专门针对Python的,当然可以拿来用,有了中文分词,可以干太多的事。但这就是后话了,不再本文中出现罗。 (2)得到目录 访问目录的操作主要是获得指定目录及从文件路径中得到相关信息。 对目录进行操作,Python把这些功能都封装到path模块中,对于不同的操作系统Python可以使用相同的方法,这便使得程序移植变得更加容易。 了解os.path模块,要从了解当前目录名和文件名入手,这分为两种情况: 1)已知一个目录 如果给定一个目录,那么我们可以使用os.path.basename()方法获得文件名,而使用os.path.dirname()获取文件前的路径。 >>> import os.path >>> filepath = r'C:\Users\lk\Desktop\Python编程入门经典.pdf' >>> os.path.basename(filepath) 'Python编程入门经典.pdf' >>> os.path.dirname(filepath) 'C:\\Users\\lk\\Desktop' OK,接下来是几种常用用法,splitdrive()取得根目录或磁盘盘符(视操作系统而定,Linux下我还没试,不知道是不是),split()分解出路径和文件全名,这时可用许多变量分别存储返回的元组中相对应的值,splitext()也是拆分并返回元组,但它最后一个值不是文件名而是文件扩展名。 >>> os.path.splitdrive(filepath) ('C:', '\\Users\\lk\\Desktop\\Python编程入门经典.pdf') >>> os.path.splitdrive('/home/lk/document/ok.py') ('', '/home/lk/document/ok.py') >>> os.path.split(filepath) ('C:\\Users\\lk\\Desktop', 'Python编程入门经典.pdf') >>> a,b = os.path.split(filepath) >>> print(a) C:\Users\lk\Desktop >>> print(b) Python编程入门经典.pdf >>> a,b = os.path.splitext(filepath) >>> print(a) C:\Users\lk\Desktop\Python编程入门经典 >>> print(b) .pdf 2)得到当前目录 如果现在你不知道你当前执行程序的路径在哪里该怎么办?好办,Python的os模块自带了getcwd()。准备no1.py文件: 在终端执行os.getcwd(),随后执行程序no1.py,请看结果: >>> os.getcwd() 'C:\\Python33' >>> ================================ RESTART ================================ >>> 程序no1.py当前路径是:C:\Users\lk\Desktop\python >>> (3)访问目录 访问目录的操作主要是进入目录、跳出目录和列出当前目录内容。 进入、跳出目录,并非像OS Shell那样与人交互,使用cd命令进入某层目录。获取目录中的内容使用os.listdir()。接着刚才的例子: >>> 程序no1.py当前路径是:C:\Users\lk\Desktop\python >>> os.listdir() ['blogtest.py', 'chapter8.py', 'mydoc.docx', 'no1.py', 'no2.py', 'no3.py', 'no4.py', 'no5.py', 'qewqeq.txt', 'Result.txt', 'temp.txt', 'Test.txt', 'test2.txt', 'wa.txt'] >>> os.mkdir('newdir') >>> os.listdir() ['blogtest.py', 'chapter8.py', 'mydoc.docx', 'newdir', 'no1.py', 'no2.py', 'no3.py', 'no4.py', 'no5.py', 'qewqeq.txt', 'Result.txt', 'temp.txt', 'Test.txt', 'test2.txt', 'wa.txt'] 从新建的newdir文件夹事实中可以看出,是有相对路径滴! 那么目录如何合成呢?很容易,目录就是字符串,合成目录就是合成字符串,可以使用os.path.join: >>> os.getcwd() 'C:\\Users\\lk\\Desktop\\python' >>> a,b = os.path.split(os.getcwd()) >>> print(a) C:\Users\lk\Desktop >>> print(b) python >>> c = "论文" >>> otherdir = os.path.join(a,c) >>> os.listdir(otherdir) ['_云计算_下的图书馆发展策略研究.kdh', '云计算XaaS概念簇的层次模型研究.doc', '云计算_图书馆事业发展的机遇与挑战.kdh', '从OCLC看图书馆云计算的未来.kdh', '博士', '基于云计算的图书馆IT应用探讨.kdh', '基于云计算的图书馆信息平台的构建.caj', '已读', '情报学报.xls', '我国云计算和图书馆相关问题研究综述.caj'] (4)改变目录 现在来看看如何改变目录,前面说过了python的os.getcwd()是获取当前工作目录,即当前python脚本工作的目录路径。 而os.chdir()则用来改变当前脚本工作目录,os.curdir用于返回当前目录,值得一提的是os.pardir用以获取当前目录的父目录字符串名。试试吧: >>> os.curdir '.' >>> os.path.pardir '..' >>> os.chdir(r'd:/') >>> os.listdir() ['$RECYCLE.BIN', '123', '360Downloads', 'Boot', 'bootmgr', 'BOOTSECT.BAK', 'foiu.ld', 'FSGLD', 'grldr', 'Media', 'Program Files', 'System Volume Information'] >>> (4)递归目录 现在来看看如何改变目,使用递归让自己解决自己的问题: import os def dir_tree(dir_path): if not os.path.isdir(dir_path): print("%s是非法目录"%(dir_path)) return False for name in os.listdir(dir_path): fullpath = os.path.join(dir_path,name) print(fullpath) if os.path.isdir(fullpath): dir_tree(fullpath) a = r"C:\Users\lk\Desktop\python" dir_tree(a) 结果如下: >>> C:\Users\lk\Desktop\python\blogtest.py C:\Users\lk\Desktop\python\chapter8.py C:\Users\lk\Desktop\python\mydoc.docx C:\Users\lk\Desktop\python\newdir C:\Users\lk\Desktop\python\no1.py C:\Users\lk\Desktop\python\no2.py C:\Users\lk\Desktop\python\no3.py C:\Users\lk\Desktop\python\no4.py C:\Users\lk\Desktop\python\no5.py C:\Users\lk\Desktop\python\no6.py C:\Users\lk\Desktop\python\no7.py C:\Users\lk\Desktop\python\qewqeq.txt C:\Users\lk\Desktop\python\Result.txt C:\Users\lk\Desktop\python\temp.txt C:\Users\lk\Desktop\python\Test.txt C:\Users\lk\Desktop\python\test2.txt C:\Users\lk\Desktop\python\top C:\Users\lk\Desktop\python\top\middle C:\Users\lk\Desktop\python\top\middle\bottom C:\Users\lk\Desktop\python\top\middle\bottom\bottom.txt C:\Users\lk\Desktop\python\top\middle.txt C:\Users\lk\Desktop\python\wa.txt >>> 4、复制/移动文件 在python中,移动、复制、重命名一个文件/文件夹是通过shutil模块实现的,在这里结合目录操作,举一个综合的例子: import os import shutil cpath = os.getcwd() #current path os.makedirs("top/middle/bottom") mpath = os.path.join(cpath,"top/middle/bottom") #modified path if os.path.isdir(mpath): os.chdir(mpath) fname = "bottom.txt" fpath = os.path.join(mpath,fname) f = open(fpath,'w') f.write('this is the end line.') f.close() if os.path.isfile(fpath): shutil.copy(fname,os.path.pardir) os.chdir(os.path.pardir) shutil.move(fname,"middle.txt") fname = "middle.txt" fpath = os.path.join(os.getcwd(),fname) f = open(fpath,'r+') tmpwords = f.read() f.seek(0,0) f.write("this is the second line.\n"+tmpwords) f.close() shutil.move(fpath,os.path.pardir) 5、判断文件/目录 以下内容的返回值True,False exists() 指定路径(文件或者目录)是否存在 isabs() 指定路径是否为绝对路径 isdir() 指定路径是否存在且为一个目录 isfile() 指定路径是否存在且为一个文件 samefile() 两个路径名是否指向同一个文件 >>> os.listdir(otherdir) ['_云计算_下的图书馆发展策略研究.kdh', '云计算XaaS概念簇的层次模型研究.doc', '云计算_图书馆事业发展的机遇与挑战.kdh', '从OCLC看图书馆云计算的未来.kdh', '博士', '基于云计算的图书馆IT应用探讨.kdh', '基于云计算的图书馆信息平台的构建.caj', '已读', '情报学报.xls', '我国云计算和图书馆相关问题研究综述.caj'] >>> os.path.exists(otherdir) True >>> os.path.isdir(otherdir+'noname') False >>> os.path.isfile(otherdir+'基于云计算的图书馆信息平台的构建.caj') False >>> os.path.isfile(os.path.join(otherdir,'基于云计算的图书馆信息平台的构建.caj')) True >>> 非常有趣的是最后两处,只用使用os.path.join()把目录和文件名组合,才能构成合法路径。哈哈。6、获得文件信息 使用以下方法获取文件相关信息: getatime() 返回最近访问时间(浮点型秒数) getctime() 返回文件创建时间 getmtime() 返回最近文件修改时间 getsize() 返回文件大小(字节为单位) abspath() 返回绝对路径 >>> filepath = os.path.join(otherdir,'基于云计算的图书馆信息平台的构建.caj') >>> os.path.isfile(filepath) True >>> os.path.getatime(filepath) 1345895347.7942 >>> os.path.getctime(filepath) 1345895347.7942 >>> os.path.getsize(filepath) 319364 >>> print("%dKB"%(os.path.getsize(filepath)/1024)) 311KB >>> os.path.abspath(filepath) 'C:\\Users\\lk\\Desktop\\论文\\基于云计算的图书馆信息平台的构建.caj' 五岳之巅原创,如有转载,必须注明出处,谢谢!
这是Oschina.net上看到的一篇文章,觉得不错,转过来。原文地址:http://www.oschina.net/news/35141/why-google-went-offline 译者注:本文中提到CloudFlare是一家总部位于美国旧金山的内容分发网络(CDN)服务公司,由Project Honey Pot项目的三位前开发人员成立于2009年。2011年10月被华尔街日报评为最具创新精神的网络科技公司。 今天,谷歌的服务经历了短暂的宕机事件,持续大概27分钟,对部分地区的互联网用户造成了影响。此次事件的原因深究起来需要进入互联网络那深邃的、 黑暗的角落。我是CloudFlare公司的一名网络工程师,在帮助谷歌从此次宕机中恢复回来提供了一臂之力。下面就是事情发生的过程。 大约在太平洋标准时间2012年11月5号下午6:24分/时间标准时间2012年11月6号凌晨2:24分,CloudFlare的员工发现谷歌 的服务中断了。我们使用谷歌的电子邮件等服务,所以,当它的服务不正常时,办公室的人会很快发现。我在网络技术小组工作,因此我立刻接上网络查看是什么情 况——是局部区域问题还是全球问题。 问题排查 我很快就意识到,所有谷歌的服务我们都不能连接上——甚至包括连接 8.8.8.8,谷歌的公共DNS服务器——于是,我从追查DNS开始。 $ dig +trace google.com 下面是我在探测Google.com的域名服务器时得到的回复: google.com. 172800 IN NS ns2.google.com. google.com. 172800 IN NS ns1.google.com. google.com. 172800 IN NS ns3.google.com. google.com. 172800 IN NS ns4.google.com. ;; Received 164 bytes from 192.12.94.30#53(e.gtld-servers.net) in 152 ms ;; connection timed out; no servers could be reached 无法探测到任何服务器的结果证明确实有什么地方出了问题。尤其是,这意味着从我们的办公室将连接不到任何的谷歌DNS服务器。 我开始网络层查找问题,看看是否是在这个通信层出了问题。 PING 216.239.32.10 (216.239.32.10): 56 data bytes Request timeout for icmp_seq 0 92 bytes from 1-1-15.edge2-eqx-sin.moratelindo.co.id (202.43.176.217): Time to live exceeded 这里出现了奇怪的信息。通常,我们不应该在谷歌的路由信息中看到一个印度尼西亚的网络服务提供商(Moratel)的名字。我立即进入一个 CloudFlare的路由器中查看发生了什么事。与此同时,Twitter上世界其它地方的报告显示了我们并不是唯一遇到问题的地方。 互联网路由 为了理解是出了什么问题,你需要知道一些互联网是如何工作的基础知识。整个互联网是由很多的网络组成,这些网络被称为是“自治系统(AS)”。每个 网络都有一个唯一的数字来标志自己,被称为AS号。CloudFlare的AS号是13335,谷歌的AS号是15169。各个网络通过一种叫做边缘网关 协议(BGP)的技术互相连接。边缘网关协议被称为是互联网的粘合剂——由它来声明哪个IP地址属于哪个网络,由它来建立从某个自治网络到另外一个自治网 络的路由。一个互联网“路由”跟这个词的表意完全一样:由一个自治网络里的IP地址到另外一个自治网络里的另一个IP地址的路径。 边缘网关协议是基于一个相互信任的体制。各个网络基于信任的原则告诉其它网络哪个IP地址属于哪个网络。当你发送一个数据包,或发送一个穿越网络的请求,你的网络服务提供商会联系它的上游提供商或对等提供商,询问它们从你的网络服务提供商到网络目的地,哪条路线最近。 不幸的是,如果当一个网络发出声明说某个IP地址或某个网络在它的内部,而事实不是这样,如果它的上游网络或对等网络信任了它,那么,这个数据包最终将会迷路丢失。这里发生的就是这个问题。 我查看了边缘网关协议传递的谷歌IP的路由地址,路由指向了Moratel (23947),一个印度尼西亚的网络服务提供商。我们的办公室在加利福尼亚,离谷歌的数据中心并不远,数据包绝不应该经过印度尼西亚。很有可能是,Moratel声明了一个错误的网络路由。 当时我看到的边缘网关协议发来的路由是: tom@edge01.sfo01> show route 216.239.34.10 inet.0: 422168 destinations, 422168 routes (422154 active, 0 holddown, 14 hidden) + = Active Route, - = Last Active, * = Both 216.239.34.0/24 *[BGP/170] 00:15:47, MED 18, localpref 100 AS path: 4436 3491 23947 15169 I > to 69.22.153.1 via ge-1/0/9.0 我查看了其它路由,比如谷歌的公共DNS,它同样被劫持到了相同的(不正确的)路径: tom@edge01.sfo01> show route 8.8.8.8 inet.0: 422196 destinations, 422196 routes (422182 active, 0 holddown, 14 hidden) + = Active Route, - = Last Active, * = Both 8.8.8.0/24 *[BGP/170] 00:27:02, MED 18, localpref 100 AS path: 4436 3491 23947 15169 I > to 69.22.153.1 via ge-1/0/9.0 路由泄漏 像这样的问题在行业内被认为是起源于“路由泄漏”,不是正常的,而是“泄漏”出来的路由。这种事情并不是没有先例。谷歌之前曾遭受过类似的宕机事件, 当时推测是巴基斯坦为了禁止YouTube上的一个视频,巴基斯坦国家ISP删除了YouTube网站的路由信息。不幸的是,他们的这种做法被传递到了外 部,巴基斯坦电信公司的上游提供商——电讯盈科(PCCW)信任了巴基斯坦电信公司的做法,把这种路由方式传递到了整个互联网。这个事件导致了 YouTube网站大约2个小时不能访问。 今天发生的事情属于类似情况。在Moratel公司的某个人很可能是“胖手指”,输错了互联网路由。而电讯盈科,Moratel公司的上游提供商, 信任了Moratel公司传递给他们的路由。很快,这错误的路由就传到了整个互联网。在边缘网关协议这种信任模式中,与其说这是恶意的行为,不如说这是误 操作或失误。 修复 解决方案就是让Moratel公司停止声明错误的路由。作为一个网络工程师,尤其是像CloudFlare这样的大网络公司里工作的工程师,很大一 部分工作就是和其它世界各地的网络工程师保持联络。当探明问题后,我联系到了Moratel公司的一位同事,告诉他发生了什么事。他大概在太平洋标准时间 下午6:50分/世界标准时间凌晨2:50分修复了这个问题。3分钟后,路由恢复了正常,谷歌的服务重新可以工作了。 从网络传输图上观察,我估计全球整个互联网用户的3-5%收到了此次宕机事故的影响。重灾区是香港,因为那是电讯盈科的总部。如果你所处的地区在当时无法访问谷歌的服务,你现在应该知道是什么原因了。 构建更好的互联网 我说这些就是想让大家知道我们的互联网上如何在一个相互信任的机制下建立起来的。今天的事故说明,即使你是一个像谷歌这样的大公司,外部你无法掌控 的因素也会影响到你的用户,让他们无法访问你,所以,一个网络技术小组是非常必要的,由他们来监控路由,管理你与世界的联系。CloudFlare公司每 天的工作就是确保客户得到最佳的路由。我们照看互联网上的所有网站,确保他们的以最快传输速度提供服务。今天的事情只是我们工作内容的一个小片段。
package mainimport ( "fmt")func main() { s := "我爱北京天安门" var t = []byte(s) p := []byte("你") t[0] = p[0] t[1] = p[1] t[2] = p[2] s = string(t) fmt.Printf("结果是:%s",s)}问题:如果修改的字符串中既有西文又有中文,该怎么截取?如何判断呢?答:可能是根据该字符的ASC大小吧。 最近太忙,没空分析,放到这里,以后再想。
为避免误会,首先声明本文前提是有合法访问身份,博文利用校园网包库形式进行登陆。PS:如果有人想问有没有外网免费访问方式呢?答案:有。请社工,然后SSL,当然这是不合情理的请大家别用,该话题点到为止,接下来转入正题。 中国知网是目前国内最大最全的综合期刊网,也是专家学者使用量最大的专业学术网站。由于近期的大研究任务需要对某杂志特定按年份进行梳理,而且第一个子任务只关心论文题目,还要保证千万不能出现作者或作者单位这样有可能影响我们判断的因素。因此,如何搜索、如何可仅得到论文题目,然后处理成格式正确可统计处理的Excel表,这便是本博文的内容。 当然,第一步就是进入期刊网,并选择“来源期刊检索”,设置年份,进行搜索: 选择你想要的文献,再点击“导出、分析...”进入下图: 接下来,很简单,全选后点击“导出/参考文献”,如上图所示。在随后出现的页面中,仍然要进行几步操作:1、自定义格式;2、选择输入内容;3、输出到TXT文件,虽然具有复制到剪切板功能,但通过我的验证这个功能目前截止发稿时无法使用。 然后,打开这份TXT文件,把里面的所有内容复制到Excel中,如下图所示: 当然,这并不是我们最后想要的格式,于是我们应该做两件事:一是把“Title题名”去掉,二是把空行去掉。具体做法如下: 用快捷键Ctrl+F弹出“查找和替换”,全部替换即可,注意替换为选项内容为空。 紧接着,选中A列,在数据选项卡中点击“删除重复项”,随后弹出的对话框直接确定就好。 由于删除的是重复空行,因而第一个空行并未视作重复项,才保留了下来。将其删除掉。 至此,全部完成,得到了只有论文名的Excel表!希望对大家有帮助。
推荐系统-从入门到精通 为了方便大家从理论到实践,从入门到精通,循序渐进系统地理解和掌握推荐系统相关知识。特做了个读物清单。大家可以按此表阅读,也欢迎提出意见和指出未标明的经典文献以丰富各学科需求(为避免初学者疲于奔命,每个方向只推荐几篇经典文献)。1. 中文综述(了解概念-入门篇)a) 个性化推荐系统的研究进展b) 个性化推荐系统评价方法综述2. 英文综述(了解概念-进阶篇)a) 2004ACMTois-Evaluating collaborative filtering recommender systemsb) 2004ACMTois -Introduction to Recommender Systems - Algorithms and evaluationc) 2005IEEEtkde Toward the next generation of recommender systems - A survey of the state-of-the-art and possible extensions3. 动手能力(实践算法-入门篇)a) 2004ACMtois Item-based top-N recommendation algorithms(协同过滤)b) 2007PRE Bipartite network projection and personal recommendation(网络结构)4. 动手能力(实践算法-进阶篇)a) 2010PNAS-Solving the apparent diversity-accuracy dilemma of recommender systems (物质扩散和热传导)b) 2009NJP Accurate and diverse recommendations via eliminating redundant correlations (多步物质扩散)c) 2008EPL Effect of initial configuration on network-based Recommendation (初始资源分配问题)5. 推荐系统扩展应用(进阶篇)a) 2009EPJB Predicting missing links via local information(相似性度量方法)b) 2010theis-Evaluating Collaborative Filtering over time(基于时间效应的博士论文)c) 2009PA Personalized recommendation via integrated diffusion on user-item-tag tripartite graphs (基于标签的三部分图方法)d) 2004LNCS Trust-aware collaborative filtering for recommender systems(基于信任机制)e) 1997CA-Fab_content-based, collaborative recommendation(基于文本信息)6. 推荐结果的解释(进阶篇)a) 2000CSCW-Explaining Collaborative Filtering Recommendationsb) 2011PRE-Information filtering via biased heat conductionc) 2011PRE- Information filtering via preferential diffusiond) 2010EPL Link Prediction in weighted networks - The role of weak tiese) 2010EPL-Solving the cold-start problem in recommender systems with social tags7. 推荐系统综合篇(专著、大型综述、博士论文)a) 2005Ziegler-thesis-Towards Decentralized Recommender Systemsb) 2010Recommender Systems Handbook 本文引用地址:http://blog.sciencenet.cn/blog-210641-508634.html
2022年02月