正则的应用--读取本地文件2--网页版解析--豆瓣

第一部分

读取本地文件

1.进入豆瓣主页,获取其网页源代码,保存下载到本地,由于代码过多,这里就不展现出来了

2.进入影评主页,获取源代码,保存下载到本地

3.在本地文件中进行解析

test.json文件中代码为:

{"body":"\n  \n  \n  \n  \n  <div class=\"main-bd\">\n\n\n    \n  \n    \n\n    <div id=\"link-report\">\n      <div property=\"v:description\"\n      class=\"review-content clearfix\"\n      data-author=\"王某某\"\n      data-url=\"https:\/\/movie.douban.com\/review\/1506795\/\"\n      data-original=\"0\">\n        我个人理解的故事脉络:<br>6个星期前,黑道巨擘Keyser Soze在正常社会中的隐身身份扮演者---小混混kint因为一件很普通的案件被带到警察局问询,问询的过程中结识了同样倒霉蛋McManus、Fenster、Todd Hockney以及好久以前认识自己的前警察But Keaton,keaton和其他三人很熟,因此可以引申到他们四人只是认为kint是一个普通的小混混而已,对他的身份毫无怀疑。在监狱中,Mcmanus提出为了向不长眼的警察们报复一下,说出了一个抢劫方案:去抢劫受警察出租车护送的携带钻石准备交易的黑道人物。这样既可以报复警察,又可以得到一批价值不菲的钻石。<br>此时的kint觉察司法部的线人Arturo Marquez知道自己过多的底细,但苦于线人受匈牙利帮的保护,杀害他的难度比较大,正好此时有这帮新认识的小兄弟,完全可以来个借刀杀人并成功脱身,kint作为如此强大的大佬,当然有能力自己解决线人的问题,但不要忘记,kint和政界有千丝万缕的联系,他不能也不可能搞成一次大的火拼,这样就会过于张扬、暴露。而此时正好有几个“可爱”的小朋友撞到“枪口”之上,并且他们这个团队具有相当强的水准:聪明而狡猾的狠角色McManus、Fenster,爆破专家:Todd Hockney,身手不错、手段高明、心狠手辣并急于想走上致富道路前警察:Keaton,当然,如此聪明的大佬kint不会傻到让团队直接去干掉线人去,他要先验一下本团队的成色,正好有此机会。他成功说服了keaton的加入,结果是明显的,战斗力强劲的团队将劫持警察出租车案件办理的天衣无缝,并且让警察惹上了大麻烦而无暇去寻找他们。<br>钻石到手后,当然得销赃,kint通过自己安排的销赃人redfoot成功将钻石出手,并引向这个团队去攻克第二件抢劫案,当然,失败是注定的,因为kint最终的目标是让团队去做掉线人,这一切都是kint安排好的合理的过度(redfoot这个角色是真实存在的,名字是杜撰的而已,kint向警察复述时是说Mcmanus认识的销赃人redfoot,这肯定是假话,因为是由redfoot这条线索引申出小林律师这个角色并引伸出Keyser Soze这个角色的,因此销赃人redfoot根本就是kint找来的),抢劫Saul失败后,他们四个人发现自己已经深深陷入Keyser Soze安排好的道路,不得不为Keyser Soze去干掉Keyser Soze的对手---那帮匈牙利人,其实,对于kint来说,匈牙利人只是一个合理的借口、诱饵罢了,真正需要干掉的是线人。他们中有人试图逃跑,被无情的杀害,于是又计划干掉接线人---小林律师,结果可以预想,又是以失败告终,因为他们当中有叛徒---kint的存在,kint成功了解到所有人的软肋,并控制他们的家人,使得他们不得不顺利听从小林律师的建议,去干掉那帮匈牙利人,同时又可得到不菲的报酬,九千一百万的现金,小林律师说的毒品只是一个混淆视听的错误的信息,因为根本就没有毒品的存在。<br>四人团队出发了,进展很顺利,在爆破专家的帮助下,炸掉了外围的一些人。Kint是参加战斗的,他向警察复述keaton让自己断后肯定是撒谎,他要干掉这次战斗中存活的其他同伴,因为他需要的是这次战斗中除他之外不能由任何生还者,当Hockney打开车门开箱看赃款的同时,kint干掉了他,然后kint又用刀子做掉了另一个同伴,最后是keaton,同时他亲手结果了线人。我想不太明白的是他为什么没有逃走?可能是当时警察已经赶到抑或他觉得他自有能力成功解脱而无需逃跑。<br>在警察局,kint运用自己的社会关系让自己很简单就被保释,但同时他听说昨晚的案件有一个匈牙利人获救,他不清楚对方究竟看到了什么,因此,当警官kujan提出向他问案时他并没有推辞,并成功运用自己的智慧漫天谎言的将自以为是的警官kujan引向误区,成功利用了kujan对keaton这个角色的误解,并根据两人谈话时得到的信息和kujan进行有效地周旋,成功将自己脱罪,并成功“无罪”的走出警察厅。个人觉得最后kujan的觉悟和kint头像传真的出现有点巧合,画蛇添足。<br><br>主要人物:<br>McManus(打家劫舍好手)<br>Fenster(McManus好友)<br>Todd Hockney(爆破专家)<br>But Keaton(前警察,力求改过自新,但又被警察以莫须有的罪名问询,心理不可承受)<br>Edie Finneran(律师,Kenton女友,真实存在的人物)<br>Verbal kint(跛子只是他惯用的一个小角色,他和keaton好久以前见过一两次,不过给keaton的印象是个小角色)<br>Keyser Soze(这只是一个代号,好像God一样,你能确定它存在吗?但你又能确定他不存在吗?kint 只是soze惯用的一个角色)<br>小林(律师,kint的得力手下之一,小林不过是他的一个符号罢了)<br><br>主要疑问之见解:<br>1、首先要肯定的是影片开始的那段the last night 是真实的发生<br>2、五个人确实是因为莫须有的罪名被问询罢了,也可能是另外完全不相干的五个人,但关键是这次是和kint 相关而已,kint 作为一个游离在社会边缘的“小角色”,当然有可能因为某一案件被警察问讯,这也更符合kint的角色,小混混吗。所以怀疑这是kint事先安排好五个人相识并不成立,只不过凑巧这次是他们五人罢了。<br>3、幸存的匈牙利人完全是个以外,kint 在船上解决完所有人之后并没有意识到还有幸存者,所以他认为所有的谎言他可以任意编造。但当他当天被带进监狱后应该知道还有幸存者,作为能量无边的Keyser Soze,不会没有他的手下想办法通知他这一切的。作为Boss,当然在黑、白两道都有自己的兄弟协助自己。所以当地方检察官提审他之前,只和他律师谈了五分钟然后就like the bogeyman,市长亲自上门过问,州长打来电话关心,老警官说具有政治色彩,这时,你还能相信kint 只是一个游离在社会边缘的小混混吗,他绝对具有很强的社会背景,所以这时可以看出kint 这个人很复杂。<br>4、为什么kint 在即将两个小时后被保释,还会接受Dave Kujan警官的询问,我认为有以下三个原因:1、kint 只知道现场有幸存者,但并不知道是怎样的角色,在昨晚事件中扮演怎样的地位。2、既然是幸存者,就有可能在隐蔽的地点看到了一些真实的情况,而kint 急需想要了解幸存者的真实情况。3、接受询问时,kint刚开始也许是想通过自己的智商和kujan警官周旋,因为kujan毕竟也没有掌握kint犯罪的事实,而当kujan警官一直引导kint将一切的幕后真正黑手指向keaton时,kint当然对此是“责无旁贷”,既可以成功的栽赃于死人keaton,作为死无对证,又可以引导kujan警官去寻找他认为还活着其实早已死去的keaton,完全把自以为聪明的kujan警官彻底引入死胡同。<br>5、关于kint 向kujan复述传说中的Soze的轶事应该是真实发生的,因为在船上时老线人当意识到Keyser Soze到来时恐惧的表情就能看出Soze是多么令人可怕的一个人,kint 就是信口开河也不能也没有必要编出自己作为Soze时所具备的心狠手辣。<br>6、Kenton女朋友的身份不用怀疑,第一,她和keaton肯定是男女朋友;第二,关于线人的案子绝对是kint 有意安排的,这样的好处是即稳住了线人,也成功掌握了keaton的软肋。最后正好杀人灭口,来个死无对证。第三,kenton在监狱中和其他四人的对话可以看出keaton确实想改邪归正,虽然这都是由kint向警察复述的,但基本可以肯定是真实的情景再现,因为此时kint还并不清楚keaton在kujan警官心目中的“形象”,也并没有从kujan警官口中套出任何有价值的信息,因此此时的信息应该是真实的,其他四个人的信息完全杜撰不得,因为船上有三个人的尸体,身份很好确定,所以kint复述五个人被警察以莫须有的罪名问询的情形基本应该是真实可信的。<br>7、小林作为kint的代言人,绝对是真实存在的,只不过小林只是个kint从办公室随处看到的一个代号而已。<br><br>本片主要看点是凯文史派西的表演,个人觉得故事结构和《洛城机密》有点差距。\n      <\/div>\n\n      \n     \n    <a rel=\"nofollow\" href=\"javascript:;\" data-rid=\"1506795\" class=\"report report_review right\">举报<\/a>\n\n\n  \n\n  <script type=\"text\/html\" id=\"template-report-popup\">\n  <div id='report_value'>\n    <ul>\n      <li>\n      <label>\n          <input type='radio' name='reason' value='0'\n          checked\n          \/> 广告或垃圾信息\n      <\/label>\n      <\/li>\n      <li>\n      <label>\n          <input type='radio' name='reason' value='1'\n          \/> 色情、淫秽或低俗内容\n      <\/label>\n      <\/li>\n      <li>\n      <label>\n          <input type='radio' name='reason' value='2'\n          \/> 激进时政或意识形态话题\n      <\/label>\n      <\/li>\n      <li>\n      <label>\n          <input type='radio' name='reason' value='other' \/> 其他原因\n      <\/label>\n      <\/li>\n    <\/ul>\n  <\/div>\n  <div class='bn-flat'>\n      <input type='submit' class='btn-report' value='举报'>\n  <\/div>\n  <\/script>\n\n\n    <\/div>\n\n    <div class=\"main-author\">\n      \n\n    <\/div>\n  <\/div>\n\n    <div class=\"main-ft\">\n      <div class=\"main-panel\" name=\"1506795\">\n        \n\n\n\n<div class=\"main-panel-useful\" data-rid=\"1506795\" data-is_owner=\"false\" data-can_vote=\"true\">\n  <button class=\"btn useful_count 1506795 \">\n    有用 642\n  <\/button>\n  <button class=\"btn useless_count 1506795 \">\n    没用 163\n  <\/button>\n    <span class=\"spoiler not-reported \" data-rid=\"1506795\">      这篇影评有剧透    <\/span>\n<\/div>\n\n      <\/div>\n    <\/div>\n","vote_script":"\n  'use strict';\n\n\/* global $, alert, get_cookie *\/\n\/* used in movie subject page *\/\n\n(function () {\n  var CONST_REVIEW_VOTE = {\n    'useful_count': ['有用', '\/j\/review\/{REVIEW_ID}\/useful'],\n    'useless_count': ['没用', '\/j\/review\/{REVIEW_ID}\/useless'],\n    'spoiler': ['剧透提醒已提交,谢谢', '\/j\/review\/{REVIEW_ID}\/spoiler']\n  };\n\n  var regDisabled = \/disabled\/,\n      regVoteType = \/(\\w+_count)\/,\n      regSpoiler = \/spoiler\/;\n\n  var votePanels = document.querySelectorAll('.main-panel-useful'),\n      votePanel = null,\n      rid = '';\n\n  var isAuthor = function isAuthor(votePanel) {\n    return votePanel && votePanel.getAttribute('data-is_owner') === 'true';\n  };\n\n  var canVote = function canVote(votePanel) {\n    return votePanel && votePanel.getAttribute('data-can_vote') === 'true';\n  };\n\n  var handleVote = function handleVote(e) {\n    e.stopPropagation();\n\n    var target = e.target;\n    var cn = target.className,\n        match = cn.match(regVoteType) || cn.match(regSpoiler),\n        type = '',\n        API_VOTE = '',\n        voteTxt = '';\n\n    if (cn.match(regDisabled)) {\n      return;\n    }\n\n    if (match) {\n      if (isAuthor(e.currentTarget)) {\n        return alert('不能给自己投票噢');\n      }\n\n      if (!canVote(e.currentTarget)) {\n        return alert('该电影还未上映,不能投票噢');\n      }\n\n      type = match[0]; \/\/ 'useful', 'useless', 'spoiler'\n      voteTxt = CONST_REVIEW_VOTE[type][0];\n      API_VOTE = CONST_REVIEW_VOTE[type][1];\n      rid = e.currentTarget.getAttribute('data-rid');\n      API_VOTE = API_VOTE.replace('{REVIEW_ID}', rid);\n    } else if (!match || !rid) {\n      return;\n    }\n\n    var voteReq = $.post(API_VOTE, { 'ck': get_cookie('ck') }, function (res) {\n      if (res.r == 0) {\n        if (type === 'spoiler') {\n          return handleSpoiler();\n        }\n        countVote(res, type);\n      }\n    });\n\n    voteReq.fail(function () {\n      alert('网络错误');\n    }).always(function () {\n      \/\/ console.log('vote ')\n    });\n  };\n\n  var handleSpoiler = function handleSpoiler(type) {\n    var reviewElem = document.getElementById(rid);\n    var spoilerElem = reviewElem.querySelector('.spoiler');\n    spoilerElem.innerText = CONST_REVIEW_VOTE['spoiler'][0];\n    spoilerElem.className = spoilerElem.className.replace('not-reported', 'disabled');\n  };\n\n  var countVote = function countVote(res, type) {\n    var reviewElem = document.getElementById(rid);\n    for (var i in CONST_REVIEW_VOTE) {\n      if (res[i] !== undefined) {\n        var countTxt = CONST_REVIEW_VOTE[i][0] + ' ' + res[i],\n            countElem = reviewElem.querySelector('.' + i),\n            _cn = countElem.className;\n\n        \/\/ 从没投过票 || 已经投票过\n        if (i === type || i !== type && _cn.match(regDisabled)) {\n          countElem.classList.toggle('disabled');\n        }\n        countElem.innerHTML = countTxt;\n      }\n    }\n  };\n\n  var len = votePanels.length;\n  for (var i = 0; i < len; i++) {\n    votePanel = votePanels[i];\n    votePanel && votePanel.addEventListener('click', handleVote, false);\n  }\n})(document);\n","votes":{"useful_count":642,"is_useless":"","is_useful":"","usecount":642,"totalcount":805,"useless_count":163},"html":"我个人理解的故事脉络:<br>6个星期前,黑道巨擘Keyser Soze在正常社会中的隐身身份扮演者---小混混kint因为一件很普通的案件被带到警察局问询,问询的过程中结识了同样倒霉蛋McManus、Fenster、Todd Hockney以及好久以前认识自己的前警察But Keaton,keaton和其他三人很熟,因此可以引申到他们四人只是认为kint是一个普通的小混混而已,对他的身份毫无怀疑。在监狱中,Mcmanus提出为了向不长眼的警察们报复一下,说出了一个抢劫方案:去抢劫受警察出租车护送的携带钻石准备交易的黑道人物。这样既可以报复警察,又可以得到一批价值不菲的钻石。<br>此时的kint觉察司法部的线人Arturo Marquez知道自己过多的底细,但苦于线人受匈牙利帮的保护,杀害他的难度比较大,正好此时有这帮新认识的小兄弟,完全可以来个借刀杀人并成功脱身,kint作为如此强大的大佬,当然有能力自己解决线人的问题,但不要忘记,kint和政界有千丝万缕的联系,他不能也不可能搞成一次大的火拼,这样就会过于张扬、暴露。而此时正好有几个“可爱”的小朋友撞到“枪口”之上,并且他们这个团队具有相当强的水准:聪明而狡猾的狠角色McManus、Fenster,爆破专家:Todd Hockney,身手不错、手段高明、心狠手辣并急于想走上致富道路前警察:Keaton,当然,如此聪明的大佬kint不会傻到让团队直接去干掉线人去,他要先验一下本团队的成色,正好有此机会。他成功说服了keaton的加入,结果是明显的,战斗力强劲的团队将劫持警察出租车案件办理的天衣无缝,并且让警察惹上了大麻烦而无暇去寻找他们。<br>钻石到手后,当然得销赃,kint通过自己安排的销赃人redfoot成功将钻石出手,并引向这个团队去攻克第二件抢劫案,当然,失败是注定的,因为kint最终的目标是让团队去做掉线人,这一切都是kint安排好的合理的过度(redfoot这个角色是真实存在的,名字是杜撰的而已,kint向警察复述时是说Mcmanus认识的销赃人redfoot,这肯定是假话,因为是由redfoot这条线索引申出小林律师这个角色并引伸出Keyser Soze这个角色的,因此销赃人redfoot根本就是kint找来的),抢劫Saul失败后,他们四个人发现自己已经深深陷入Keyser Soze安排好的道路,不得不为Keyser Soze去干掉Keyser Soze的对手---那帮匈牙利人,其实,对于kint来说,匈牙利人只是一个合理的借口、诱饵罢了,真正需要干掉的是线人。他们中有人试图逃跑,被无情的杀害,于是又计划干掉接线人---小林律师,结果可以预想,又是以失败告终,因为他们当中有叛徒---kint的存在,kint成功了解到所有人的软肋,并控制他们的家人,使得他们不得不顺利听从小林律师的建议,去干掉那帮匈牙利人,同时又可得到不菲的报酬,九千一百万的现金,小林律师说的毒品只是一个混淆视听的错误的信息,因为根本就没有毒品的存在。<br>四人团队出发了,进展很顺利,在爆破专家的帮助下,炸掉了外围的一些人。Kint是参加战斗的,他向警察复述keaton让自己断后肯定是撒谎,他要干掉这次战斗中存活的其他同伴,因为他需要的是这次战斗中除他之外不能由任何生还者,当Hockney打开车门开箱看赃款的同时,kint干掉了他,然后kint又用刀子做掉了另一个同伴,最后是keaton,同时他亲手结果了线人。我想不太明白的是他为什么没有逃走?可能是当时警察已经赶到抑或他觉得他自有能力成功解脱而无需逃跑。<br>在警察局,kint运用自己的社会关系让自己很简单就被保释,但同时他听说昨晚的案件有一个匈牙利人获救,他不清楚对方究竟看到了什么,因此,当警官kujan提出向他问案时他并没有推辞,并成功运用自己的智慧漫天谎言的将自以为是的警官kujan引向误区,成功利用了kujan对keaton这个角色的误解,并根据两人谈话时得到的信息和kujan进行有效地周旋,成功将自己脱罪,并成功“无罪”的走出警察厅。个人觉得最后kujan的觉悟和kint头像传真的出现有点巧合,画蛇添足。<br><br>主要人物:<br>McManus(打家劫舍好手)<br>Fenster(McManus好友)<br>Todd Hockney(爆破专家)<br>But Keaton(前警察,力求改过自新,但又被警察以莫须有的罪名问询,心理不可承受)<br>Edie Finneran(律师,Kenton女友,真实存在的人物)<br>Verbal kint(跛子只是他惯用的一个小角色,他和keaton好久以前见过一两次,不过给keaton的印象是个小角色)<br>Keyser Soze(这只是一个代号,好像God一样,你能确定它存在吗?但你又能确定他不存在吗?kint 只是soze惯用的一个角色)<br>小林(律师,kint的得力手下之一,小林不过是他的一个符号罢了)<br><br>主要疑问之见解:<br>1、首先要肯定的是影片开始的那段the last night 是真实的发生<br>2、五个人确实是因为莫须有的罪名被问询罢了,也可能是另外完全不相干的五个人,但关键是这次是和kint 相关而已,kint 作为一个游离在社会边缘的“小角色”,当然有可能因为某一案件被警察问讯,这也更符合kint的角色,小混混吗。所以怀疑这是kint事先安排好五个人相识并不成立,只不过凑巧这次是他们五人罢了。<br>3、幸存的匈牙利人完全是个以外,kint 在船上解决完所有人之后并没有意识到还有幸存者,所以他认为所有的谎言他可以任意编造。但当他当天被带进监狱后应该知道还有幸存者,作为能量无边的Keyser Soze,不会没有他的手下想办法通知他这一切的。作为Boss,当然在黑、白两道都有自己的兄弟协助自己。所以当地方检察官提审他之前,只和他律师谈了五分钟然后就like the bogeyman,市长亲自上门过问,州长打来电话关心,老警官说具有政治色彩,这时,你还能相信kint 只是一个游离在社会边缘的小混混吗,他绝对具有很强的社会背景,所以这时可以看出kint 这个人很复杂。<br>4、为什么kint 在即将两个小时后被保释,还会接受Dave Kujan警官的询问,我认为有以下三个原因:1、kint 只知道现场有幸存者,但并不知道是怎样的角色,在昨晚事件中扮演怎样的地位。2、既然是幸存者,就有可能在隐蔽的地点看到了一些真实的情况,而kint 急需想要了解幸存者的真实情况。3、接受询问时,kint刚开始也许是想通过自己的智商和kujan警官周旋,因为kujan毕竟也没有掌握kint犯罪的事实,而当kujan警官一直引导kint将一切的幕后真正黑手指向keaton时,kint当然对此是“责无旁贷”,既可以成功的栽赃于死人keaton,作为死无对证,又可以引导kujan警官去寻找他认为还活着其实早已死去的keaton,完全把自以为聪明的kujan警官彻底引入死胡同。<br>5、关于kint 向kujan复述传说中的Soze的轶事应该是真实发生的,因为在船上时老线人当意识到Keyser Soze到来时恐惧的表情就能看出Soze是多么令人可怕的一个人,kint 就是信口开河也不能也没有必要编出自己作为Soze时所具备的心狠手辣。<br>6、Kenton女朋友的身份不用怀疑,第一,她和keaton肯定是男女朋友;第二,关于线人的案子绝对是kint 有意安排的,这样的好处是即稳住了线人,也成功掌握了keaton的软肋。最后正好杀人灭口,来个死无对证。第三,kenton在监狱中和其他四人的对话可以看出keaton确实想改邪归正,虽然这都是由kint向警察复述的,但基本可以肯定是真实的情景再现,因为此时kint还并不清楚keaton在kujan警官心目中的“形象”,也并没有从kujan警官口中套出任何有价值的信息,因此此时的信息应该是真实的,其他四个人的信息完全杜撰不得,因为船上有三个人的尸体,身份很好确定,所以kint复述五个人被警察以莫须有的罪名问询的情形基本应该是真实可信的。<br>7、小林作为kint的代言人,绝对是真实存在的,只不过小林只是个kint从办公室随处看到的一个代号而已。<br><br>本片主要看点是凯文史派西的表演,个人觉得故事结构和《洛城机密》有点差距。"}

4.之前提到ip被封,挂了代理ip之后,也无法获取到数据

挂载代理ip方法如下:

headers = {
        'Host': "douban.com",
        'User-Agent': agent.random,
        'Accept': 'text/css,*/*;q=0.1',
        'Cookie': ''
    }
    proxy = request.ProxyHandler({
        'http': '61.135.217.7:80'
    })
    openner = request.build_opener(proxy)
    request.install_opener(openner)
    req = request.Request('https://movie.douban.com/top250', headers=headers)
    resp = openner.open(req)
5.文件中需要引入的包
# -*- coding:utf-8 -*-
from urllib import request
import codecs
import re
import json
import time
from fake_useragent import UserAgent
agent = UserAgent()

6.代码思路:
    1.在get_html 中根据url地址,获取目标数据,判断请求的是否为完整影评的json数据,如果是将返回的数据赋值给json属性,如果不是就赋值html属性
    2.在parse_list函数中,根据正则解析当前页的所有电影的链接,拼接完整的影评链接地址,发送请求,解析影评数据,  找到下一页的链接,发送请求,重新调用parse_list函数解析下一页数据....

    3.在parse_comments()函数中,根据正则解析当前页的所有影评信息,for遍历,找到每一个影评id,根据id拼接完整的影评地址,发送请求,解析完整影评,处理数据,提取分数,输出或保存..... 查找下一页的链接,拼接地址,发送请求,重新调用parse_comments()函数解析数据..

7.注意:

从执行结果可以看出 所有的评论是一样的原因是:

在def parse_comments(self):函数中循环执行的是同一个json文件中的数据,里面只包含一条 样本!

完整代码:

# -*- coding:utf-8 -*-
from urllib import request
import codecs
import re
import json
import time
from fake_useragent import UserAgent
agent = UserAgent()
 
class DBSpider(object):

    def __init__(self):
        with codecs.open('douban.html', 'r', encoding='utf-8') as f:
            self.html = f.read()

    def parse_list(self):
        pattern = re.compile('<div class="hd.*?href="(.*?)"', re.S)
        res = re.findall(pattern, self.html)
        # for循环遍历列表,取出每一个电影信息
        for link in res:
            # 拼接完整的电影影评地址
            url = link + 'reviews'
            # 发起请求,拿回影评页面
            with codecs.open('detail.html', 'r', encoding='utf-8')as f:
                self.html = f.read()
                # 解析详情页的数据
                self.parse_comments()
        # 找下一页
        pattern = re.compile('<link rel="next" href="(.*?)"')
        res = re.search(pattern, self.html)
        if res:
            # 拼接下一页的url地址
            next_href = 'https://movie.douban.com/top250?' + res.group(1)
            # 发起请求,拿回下一页数据
            # 调用此函数,解析数据
        else:
            print('没有下一页')

    # 解析影评页面
    def parse_comments(self):
        pattern = re.compile('<div class="main review-item.*?id="(.*?)".*?v:reviewer.*?>(.*?)</a>.*?<span.*?class="(.*?)".*?title="(.*?)".*?<span.*?>(.*?)</span', re.S)
        res = re.findall(pattern, self.html)
        # for 循环遍历数据
        for ID, name, star, suggest, date in res:
            # 根据url发送请求,拿回完整的影评信息
            url = 'https://movie.douban.com/j/review/%s/full' % ID
            # 循环执行一个json文件中的数据,所以输出的 评论 是一个评论
            with codecs.open('test.json', 'r', encoding='utf-8')as f:
                info = f.read()
                com_dict = json.loads(info)
                comment = com_dict.get('html')
                # 处理数据
                comment = re.sub(re.compile('<br>'), '\n', comment)
                comment = re.sub(re.compile('<.*?>|\n| ', re.S), '', comment)
            # 把影评分数分割出来
            score = re.search(re.compile('\d+'), star).group()
            print('作者:{}\n作者ID:{}\n分数:{}\n建议:{}\n发布日期:{}\n评价内容:{}\n'.format(name, ID, score, suggest, date, comment))
            # 找下一页
            pattern = re.compile('<link rel="next" href="(.*?)"')
            res = re.search(pattern, self.html)
            if res:
                # 拼接下一页url地址
                next_href = url + res.group()
                # 发起请求,拿回下一页数据
                # 调用此函数,解析数据
                # self.parse_comments()
            else:
                print('没有下一页')

    def start(self):
        self.parse_list()


if __name__ == '__main__':
    dbdy = DBSpider()
    dbdy.start()

执行结果:



第二部分

网页解析:

具体解析和解析本地文件差不多,不做过多解释

实现思路:

'''
    1.在get_html 中根据url地址,获取目标数据,判断请求的是否为完整影评的json数据,如果是将返回的数据赋值给json属性,如果不是就赋值html属性
    2.在parse_list函数中,根据正则解析当前页的所有电影的链接,拼接完整的影评链接地址,发送请求,解析影评数据,  找到下一页的链接,发送请求,重新调用parse_list函数解析下一页数据....
    3.在parse_comments()函数中,根据正则解析当前页的所有影评信息,for遍历,找到每一个影评id,根据id拼接完整的影评地址,发送请求,解析完整影评,处理数据,提取分数,输出或保存..... 查找下一页的链接,拼接地址,发送请求,重新调用parse_comments()函数解析数据..
'''

完整代码:

from urllib import request
import codecs
import re
import json
import time


class DBSpider(object):

    def __init__(self):

        # 读取本地文件,做数据的解析
        # with codecs.open('douban.html','r',encoding='utf-8') as f:
        #     self.html = f.read()

        self.html = ''
        # 发请求的话,需要带上登录之后的cookie
        self.headers = {
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Cookie':'ll="128517"; bid=JWYJzKhS_Vc; __yadk_uid=t8sJyKbxnVnF3NFso9uRLV8WW0oJDKxH; _vwo_uuid_v2=D639114FFF67EC089E7D03E92504EBEC5|8ba743c5c00bd36a97c0fec4da764061; ps=y; dbcl2="175108542:665ypl9UG1Q"; ck=MI-6; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1520490928%2C%22https%3A%2F%2Fwww.douban.com%2Faccounts%2Flogin%3Fredir%3Dhttps%253A%252F%252Fmovie.douban.com%252Ftop250%253Fqq-pf-to%253Dpcqq.group%22%5D; _pk_ses.100001.4cf6=*; push_noty_num=0; push_doumail_num=0; _pk_id.100001.4cf6=b7a8892258d1a5dd.1517454912.4.1520493388.1520478251.',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'
        }
    # 获取html源代码
    def get_html(self,url):
        # 发请请求
        req = request.Request(url, headers=self.headers)
        response = request.urlopen(req)
        # 判断是否为json数据,包含的是完整影评
        if '/full' in url:
            self.json = response.read().decode('utf-8')
        else:
            self.html = response.read().decode('utf-8')
        time.sleep(2)

    # 解析首页列表
    def parse_list(self):
        pattern = re.compile('<div class="hd.*?href="(.*?)"',re.S)
        res = re.findall(pattern,self.html)
        # for循环遍历列表,取出每一个电影信息
        for link in res:
            # 拼接完整的电影影评地址
            url = link + 'reviews'
            # 发起请求,拿回影评页面
            self.get_html(url)
            # 解析详情
            self.parse_comments(url)

            # 读取本地文件,做数据解析
            # with codecs.open('detail.html','r',encoding='utf-8') as f:
            #     # 详情html
            #     self.html = f.read()
            #     # 解析详情页面的数据
            #     self.parse_comments(url)

        # 找下一页
        pattern = re.compile('<link rel="next" href="(.*?)"')
        res = re.search(pattern,self.html)
        if res:
            # 拼接下一页的url地址
            next_href= 'https://movie.douban.com/top250?'+res.group(1)
            # 发起请求,拿回下一页数据
            self.get_html(next_href)
            # 调用此函数,解析数据
            self.parse_list()
        else:
            print('没有下一页')


    # 解析影评页面
    def parse_comments(self,url):

        pattern = re.compile('<div class="main review-item.*?id="(.*?)".*?v:reviewer.*?>(.*?)</a>.*?<span.*?class="(.*?)".*?title="(.*?)".*?<span.*?>(.*?)</span',re.S)
        res = re.findall(pattern,self.html)
        # for循环遍历数据
        for ID,name,star,suggest,date in res:

            # 读取本地数据,做数据解析
            # with codecs.open('test.json','r',encoding='utf-8') as f:
            #     info = f.read()
            #     com_dict = json.loads(info)
            #     comment = com_dict.get('html')
            #     comment = re.sub(re.compile('<br>'),'\n',comment)

            # 根据url发送请求,拿回完整的影评信息
            url = 'https://movie.douban.com/j/review/%s/full' % ID
            self.get_html(url)
            com_dict = json.loads(self.json)
            comment = com_dict.get('html')
            # 处理数据
            comment = re.sub(re.compile('<br>'),'\n',comment)
            comment = re.sub(re.compile('<.*?>|\n| ',re.S),'',comment)
            # 把影评分数匹配出来
            sorce = re.search(re.compile('\d+'),star).group()

            print('作者:{}\n作者ID:{}\n分数:{}\n建议:{}\n发布日期:{}\n评价内容:{}'.format(name,ID,sorce,suggest,date,comment))


        # 找下一页
        pattern = re.compile('<link rel="next" href="(.*?)"')
        res = re.search(pattern,self.html)
        if res:
            # 拼接下一页的url地址
            next_href = url + res.group(1)
            # 发起请求,拿回下一页数据
            self.get_html(next_href)
            # 调用此函数,解析数据
            self.parse_comments(url)
        else:
            print('没有下一页')

    def start(self):

        self.get_html('https://movie.douban.com/top250?qq-pf-to=pcqq.group')
        self.parse_list()


if __name__ == '__main__':

    db = DBSpider()
    db.start()

运行结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值