Python3爬虫新手项目详解:爬取豆瓣读书的前50条评论内容并显示评分。提示:有的评论不包含评分

爬取《三体》,相关网页内容如下:

https://book.douban.com/subject/2567698/comments/hot?p=1

开始之前我们先明确一下爬虫的基本步骤:

  • 抓取
    • urllib内建模块 urllib.request
    • requests第三方库(中小型)
    • scrapy框架(大型)
  • 解析
    • BeautifulSoup库
    • re模块

这次我们就用到了requests库,BeautifulSoup库以及re模块

由于要读取50条短评,而每一页有20条,用一个while循环解决,第一页是p=1,第二页是p=2,以此类推。

观察评分和评论部分的网页源代码如下:

    <span class="comment-info">
        <a href="https://www.douban.com/people/petercat/">Peter Cat</a>
            <span class="user-stars allstar40 rating" title="推荐"></span>
        <span>2014-08-05</span>
    </span>
</h3>
<p class="comment-content">
            
    <span class="short">大刘不是文笔平庸,是根本没有文笔和人物。三体之所以仍旧很好看,的确仰赖其在物理、历史、数学、哲学方面极其渊博的知识,和将这些知识串联起来的想象力。不过还是会觉得遗憾,没有心理建构小说,那种震撼永远是表层的。</span>

可以发现"user-stars allstar40 rating"里的40是评分,而<span class="short">中的内容是评论,评论很容易用BeautifulSoup解析得到,而评分用re模块进行解析。需要注意的是第三页全部读到列表里的话就会总共有60条,所以用count_del记录一下,最后再删掉多余的。上代码:

# -*- coding: utf-8 -*-
import requests
import re
from bs4 import BeautifulSoup
count=count_del=0
allstars=[]
i=1
while count<50:
    try:
        r=requests.get('https://book.douban.com/subject/2567698/comments/hot?p='+str(i))
    except:
        print('fail to crawl!')
        break
    soup=BeautifulSoup(r.text,'lxml')
    comments=soup.find_all('span','short')
    pattern=re.compile(r'<span class="user-stars allstar(.*?) rating"')
    stars=pattern.findall(r.text)
    allstars.extend(stars)
    for item in comments:
        if count<50:
            print(count+1,item.string)
            count+=1
        else:
            count_del+=1
    i+=1
#有点问题,最后被截去的评论可能没有评分,就会把原本位于前50的评分删掉
remainStars=allstars[:-count_del]
print(len(remainStars),'-->',remainStars)

但是这时有个问题就是假如最后10条有的评论没评分,那么删去的10个评分中就会有位于前50的评分,这不是我们想要的。


改进

改进之处在于把没打分的一项单独识别并显示出来。观察网页源代码发现没打分的部分缺少了一行

打分的:
    <a href="https://www.douban.com/people/bighead/">大头绿豆</a>
        <span class="user-stars allstar50 rating" title="力荐"></span>
    <span>2017-03-03</span>
没打分的:        
    <a href="https://www.douban.com/people/duanmuyi/">小波福娃</a>
    <span>2013-03-21</span>


,而上下都是一样的,据此写出正则表达式,提取出来这一部分,根据这一部分的有无来设置分数的有无。尤其要注意的是上下行之间存在着\n和许多空格,所以正则表达式中的\s*很关键

也可以加参数re.S使得(.*?)匹配到\n,但是这样findall()会把没有打分的也匹配了一个字符串'\n     ',这样search()方法就会匹配到None,不如让findall()匹配到空'',更好操作。

  • 改进后的代码:
# -*- coding: utf-8 -*-
import requests
import re
from bs4 import BeautifulSoup
count=0
i=1
while count<50:
    try:
        r=requests.get('https://book.douban.com/subject/2567698/comments/hot?p='+str(i))
    except:
        print('fail to crawl!')
        break
    soup=BeautifulSoup(r.text,'lxml')
    comments=soup.find_all('span','short')
    pattern1=re.compile(r'<a href="https://www.douban.com/people.*?</a>\s*(.*?)\s*<span>.*?</span>')
    pattern2=re.compile(r'<span class="user-stars allstar(.*?) rating" ')
    stars=pattern1.findall(r.text)
    for j in range(len(stars)):
        if stars[j]:
            stars[j]=int(pattern2.search(stars[j]).group(1))
        else:
            stars[j]=None
    for j in range(len(comments)):
        if count==50:
            break
        if stars[j]:
            print(count+1,stars[j],comments[j].string)
        else:
            print(count+1,'No star',comments[j].string)
        count+=1
    i+=1

 

  • 爬取结果:
...
16 40 毕竟还在用“就像小鸟眷恋着天空”这样的比喻,算了,都是文科生的矫情。
17 20 终于正式全部看完了,终于可以正式表示不好看。。。
18 40 星空如此浩瀚,人们却只能为蜗居浪费一生。活该被鄙视:你们是虫子。
19 20 对于这部几乎被誉为“当代中国最高科幻水准”的科幻大作,我却很难从中得到任何阅读的快感,反而是为了一探究竟(到底它牛逼在哪里)的心态支持我看完。虽然已经在看第二部,但目前还没发现有什么惊喜出现,且由于大量的物理名词出现,使得阅读感越来越差。
20 No star 不爱跟风所以拖到现在才读过传说中的三体,作为小说它的技巧叙述手法和人物塑造简直惨不忍睹(多年前第一次读刘慈欣到现在他的文学修养怎么一点长进都没有),但是故事的内核很饱满丰富,干货多,粗糙但不乏深刻,坚强一点的话可以无视文笔技巧挺过去读完。3.5星吧。
21 20 糟糕的人设和跳脱的情节硬是把一个绝佳的概念写得毫无趣味。
...
48 30 了得小姐推荐的,可是,看了一天加一晚,睡着过去三次,我是真的很认真努力了。可是先把理念架构放一边,作者写故事的能力实在欠佳。也可能是从小看书到大胃口已经逐渐刁钻,最介意的除了故事性和作者的思想,首先要求文风老辣。
49 No star 长途重新读了一遍。终于发现三体1确实还是写得比较糙的……以及从热门划线里,可以分析出现在读者的口味……
50 30 科幻足够硬,脑洞足够大,文笔足够俗,三观足够雷,奇葩,奇葩奇葩

可以发现第20个人(也就是第一页的最后一个人)没有打分。
注意加了re.S的区别,以及\s*匹配到'\n     '的细节
 

>>> import re 
>>> pattern=re.compile(r'<a href="https://www.douban.com/people.*?</a>\s*(.*?)\s*<span>.*?</span>')
>>> s='''
... </span>
                <span class="comment-info">
                    <a href="https://www.douban.com/people/bighead/">大头绿豆</a>
                        <span class="user-stars allstar50 rating" title="力荐"></span>
                    <span>2017-03-03</span>
                </span>
            </h3>'''
... ... ... ... ... ... >>> pattern.findall(s)
['<span class="user-stars allstar50 rating" title="力荐"></span>']
>>> s
'\n</span>\n                <span class="comment-info">\n                    <a href="https://www.douban.com/people/bighead/">大头绿豆</a>\n                        <span class="user-stars allstar50 rating" title="力荐"></span>\n                    <span>2017-03-03</span>\n                </span>\n            </h3>'
>>> pattern=re.compile(r'<a href="https://www.douban.com/people.*?</a>(.*?)<span>.*?</span>',re.S)
>>> pattern.findall(s)
['\n                        <span class="user-stars allstar50 rating" title="力荐"></span>\n                    ']

>>> re.findall(r'a.*?b','aba9b a \t  b  a\n b a\nb')
['ab', 'a9b', 'a \t  b']
>>> re.findall(r'a.*?b','aba9b a \t  b  a\n b a\nb',re.S)
['ab', 'a9b', 'a \t  b', 'a\n b', 'a\nb']

 

 

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值