[Python]豆瓣用户读书短评下载工具

简介

朋友问我能不能做一个下载他在豆瓣读书上的短评的工具,于是就做了这个“豆瓣用户读书短评下载工具”。
GitHub链接:https://github.com/xiaff/dbc-downloader

这个小工具使用Python3.4编写,其工作流程为:

  1. 用户输入其豆瓣ID;
  2. 抓取用户评论列表网页
  3. 对网页进行解析;
  4. 存储评论相关信息;
  5. 将Markdown格式文件转换为Html。

用到的库主要有:

  • urllib.request
  • BeautifulSoup4
  • markdown

抓取网页

所需要抓取的信息在这样的网页中:http://book.douban.com/people/ahbei/collect?sort=time&start=0&filter=all&mode=grid&tags_sort=count,URL中包含了用户ID(people/之后)、评论序号(start=)等信息。

url_1=‘http://book.douban.com/people/‘
url_2=‘/collect?sort=time&start=‘
url_3=‘&filter=all&mode=grid&tags_sort=count‘

url=url_1+uId+url_2+index+url_3,其中 UID 为豆瓣用户ID,index 为评论序号。评论序号从0开始编号,每页显示15条,因为每个url中的序号依次为0、15、30……15*i。 i的最大值即为 网页页数-1,在解析第一张网页的时候可以获取页数。

在抓取网页的时候可以选择使用代理服务器,因此使用urllib.request设置代理:

proxyInfo=input(‘Please type in your HTTP Proxy: ‘)
proxySupport=urllib.request.ProxyHandler({‘http‘:proxyInfo})
opener=urllib.request.build_opener(proxySupport)
urllib.request.install_opener(opener)

不过,如果只设置了代理就访问豆瓣的用户读书评论列表,豆瓣会返回403 Forbidden
解决办法就是添加请求标头(Request Headers)来模拟浏览器访问。 标头信息可以在浏览器中打开网页时按F12进入控制台,在Network选项卡中找到 请求标头(Request Headers)
比如,这是我在Edge浏览器中访问豆瓣的请求标头。

head= {
   ‘Accept‘:‘text/html, application/xhtml+xml, image/jxr, */*‘,
   ‘Accept-Language‘: ‘zh-Hans-CN, zh-Hans; q=0.5‘,
   ‘Connection‘:‘Keep-Alive‘,
   ‘Cookie‘:‘bid=lkpO8Id/Kbs; __utma=30149280.1824146216.1438612767.1440248573.1440319237.13; __utmz=30149280.1438612767.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); as=http://book.douban.com/people/133476248/; ll=108288; viewed=26274009_1051580; ap=1; ps=y; ct=y; __utmb=30149280.23.10.1440319237; __utmc=30149280; __utmt_douban=1; _pk_id.100001.3ac3=b288f385b4d73e38.1438657126.3.1440319394.1440248628.; __utma=81379588.142106303.1438657126.1440248573.1440319240.3; __utmz=81379588.1440319240.3.2.utmcsr=movie.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_ses.100001.3ac3=*; __utmb=81379588.23.10.1440319240; __utmt=1; __utmc=81379588; _pk_ref.100001.3ac3=%5B%22%22%2C%22%22%2C1440319240%2C%22http%3A%2F%2Fmovie.douban.com%2F%22%5D‘,
   ‘Host‘:‘book.douban.com‘,
   ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240‘}

然后在访问网页的时候加上header信息:

full_url=urllib.request.Request(url,headers=head)
response=urllib.request.urlopen(full_url)
html=response.read()

这样就可以正确抓取到网页内容了。

解析网页

在我之前一片文章[Python]从豆瓣电影批量获取看过某部电影的用户列表讲过了使用 BeautifulSoup 解析网页了,其实只要看看官方文档就很容易上手了。 这里就不再赘述了。

Markdown转Html

最后一步是将以Markdown格式保存的文件转换成Html文件,这样可以让不熟悉Markdown的人在浏览器中直接查看或者另存为PDF文件。
markdown包可以做到这一点:

md = markdown.markdown(contents)
html = ‘<html><meta charset="UTF-8">‘
html+=‘<title>‘+title+‘</title>‘
html += "<body>" + md + "</body></html>"

md = markdown.markdown(contents)转换出来的md是不包含<html>标签的,因此需要自己加上这些标签后再保存。

源代码

#coding=utf-8
#Python 3.4
##从豆瓣网页中得到用户的所有读书短评

##网页地址类型:http://book.douban.com/people/1000001/collect?sort=time&start=0&filter=all&mode=grid&tags_sort=count
##            http://book.douban.com/people/1000001/collect?sort=time&start=15&filter=all&mode=grid&tags_sort=count

from bs4 import BeautifulSoup
import time
import urllib.request,urllib.parse
from urllib.error import URLError,HTTPError
import os
import markdown

#换行符
lineSep=‘\n‘

#设置HTTP代理
ans=input(‘Do you want to use a HTTP Proxy (N/y)? ‘)
ans=ans.lower()
if ans==‘y‘ or ans==‘yes‘:
    print(‘HTTP Proxy formart: IP:PORT \nExample: 127.0.0.1:80‘)
    print(‘Do NOT contain any unnecessary characters.‘)
    proxyInfo=input(‘Please type in your HTTP Proxy: ‘)
    proxySupport=urllib.request.ProxyHandler({‘http‘:proxyInfo})
    opener=urllib.request.build_opener(proxySupport)
    urllib.request.install_opener(opener)
else:
    pass

#头信息
head= {
   ‘Accept‘:‘text/html, application/xhtml+xml, image/jxr, */*‘,
   ‘Accept-Language‘: ‘zh-Hans-CN, zh-Hans; q=0.5‘,
   ‘Connection‘:‘Keep-Alive‘,
   ‘Cookie‘:‘bid=lkpO8Id/Kbs; __utma=30149280.1824146216.1438612767.1440248573.1440319237.13; __utmz=30149280.1438612767.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); as=http://book.douban.com/people/133476248/; ll=108288; viewed=26274009_1051580; ap=1; ps=y; ct=y; __utmb=30149280.23.10.1440319237; __utmc=30149280; __utmt_douban=1; _pk_id.100001.3ac3=b288f385b4d73e38.1438657126.3.1440319394.1440248628.; __utma=81379588.142106303.1438657126.1440248573.1440319240.3; __utmz=81379588.1440319240.3.2.utmcsr=movie.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_ses.100001.3ac3=*; __utmb=81379588.23.10.1440319240; __utmt=1; __utmc=81379588; _pk_ref.100001.3ac3=%5B%22%22%2C%22%22%2C1440319240%2C%22http%3A%2F%2Fmovie.douban.com%2F%22%5D‘,
   ‘Host‘:‘book.douban.com‘,
   ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240‘}

#url=url_1+uId+url_2+Index+url_3
url_1=‘http://book.douban.com/people/‘
url_2=‘/collect?sort=time&start=‘
url_3=‘&filter=all&mode=grid&tags_sort=count‘

def is_chinese(uchar):
    """判断一个unicode是否是汉字
    """
    if uchar >= u‘\u4e00‘ and uchar<=u‘\u9fa5‘:
        return True
    else:
        return False

def isChineseBook(title):
    """判断书名是否为中文书名
    """
    for c in title:
        if(is_chinese(c)):
            return True
    return False

def getHtml(url):
    """返回指定的网页内容
    """
    print(‘Loading: ‘+url+‘......‘)
    full_url=urllib.request.Request(url,headers=head)
    TRY_TIMES=3
    response=None
    while TRY_TIMES>0 and response==None :
        TRY_TIMES-=1
        try:
            response=urllib.request.urlopen(full_url)   #open=urlopen
        except HTTPError as e:
            print(‘HTTP Error:‘,e.code)
        except URLError as e:
            print(‘URL Error: ‘,e.reason)
    if response==None:
        print(‘Error!‘)
        os.system("pause")
        exit()
    html=response.read()
    return html

def getBookComment(html):
    """解析网页并返回5个列表:
    书名,出版信息,标记日期,标签,评论
    """
    titleList=[]    #书名
    pubList=[]      #出版信息
    dateList=[]     #标记日期
    tagsList=[]     #标签
    commentList=[]  #评论

    soup=BeautifulSoup(html,‘html.parser‘)
    lis=soup.findAll(‘li‘,‘subject-item‘)
    for li in lis:
        infoDiv=li.find(‘div‘,‘info‘)
        commentP=infoDiv.find(‘p‘,‘comment‘)
        if commentP!=None:
            a=infoDiv.a
            #书名
            title1=a.get(‘title‘).strip()
            title2Span=a.span
            if title2Span!=None:
                title2=a.span.text.strip()
            else:
                title2=‘‘
            title=title1+title2
            c1=title[0]
            c2=title[-1]
            #如果是中文书名,则加上书名号
            if isChineseBook(title):
                title=u‘《‘+title+u‘》‘
            else:   #英文书加斜体
                title=‘*‘+title+‘*‘
            titleList.append(title)
            #出版信息
            pubDiv=infoDiv.find(‘div‘,‘pub‘)
            pub=pubDiv.text.strip()
            pubList.append(pub)
            #标记日期
            dataSpan=infoDiv.find(‘span‘,‘date‘)
            words=dataSpan.text.split(‘\n‘)
            date=words[0]+words[1]
            dateList.append(date)
            #标签
            tagsSpan=infoDiv.find(‘span‘,‘tags‘)
            if tagsSpan!=None:
                tags=tagsSpan.text.strip()
            else:
                tags=‘‘
            tagsList.append(tags)
            #评论
            comment=commentP.text.strip()
            commentList.append(comment)
    return (titleList,pubList,dateList,tagsList,commentList)

def getHtmlTitle(html):
    """
    获取网页标题
    """
    soup=BeautifulSoup(html,‘html.parser‘)
    title=soup.head.title.text
    return title

def clearOldFile(uId):
    """
    清除之前已保存的文件
    """
    fileName=‘booksComments_‘+uId+‘.md‘
    temp=open(fileName,‘w‘,encoding=‘utf-8‘)
    temp.close()

def saveBookComment(titleList,pubList,dateList,tagsList,commentList,uId):
    """保存书评至文件
    """
    fileName=‘booksComments_‘+uId+‘.md‘
    wf=open(fileName,mode=‘a‘,encoding=‘utf-8‘)
    size=len(titleList)
    for i in range(size):
        title=titleList[i]
        pub=pubList[i]
        date=dateList[i]
        tags=tagsList[i]
        comment=commentList[i]
        wf.write(‘## ‘+title+lineSep)
        wf.write(pub+‘  ‘+lineSep)
        wf.write(date+‘  ‘+lineSep)
        wf.write(tags+lineSep+lineSep)
        wf.write(comment+lineSep+lineSep)
    wf.close()
    return fileName

def getPageNum(html):
    """解析第一页网页,返回该用户的书评页数
    """
    soup=BeautifulSoup(html,‘html.parser‘)
    paginator=soup.find(‘div‘,‘paginator‘)
    pas=paginator.findAll(‘a‘)
    num=int(pas[-2].text)
    return num

def convertMd2Html(mdName,title):
    """
    将Markdown文件转换为Html格式文件
    """
    htmlName=mdName.replace(‘.md‘,‘.html‘)
    mdFile=open(mdName,‘r‘,encoding=‘utf-8‘)
    contents=mdFile.read()
    mdFile.close()
    md = markdown.markdown(contents)
    html = ‘<html><meta charset="UTF-8">‘
    html+=‘<title>‘+title+‘</title>‘
    html += "<body>" + md + "</body></html>"
    htmlFile=open(htmlName,‘w‘,encoding=‘utf-8‘)
    htmlFile.write(html)
    htmlFile.close()
    return htmlName

#输入User-Id
print(‘\nYou can find User-Id in the url.‘)
print(‘E.g. Someone\‘s homepage\‘url is http://book.douban.com/people/1000001/ , the User-Id should be 1000001 .‘)
uId=input(‘User-Id: ‘)
while(uId==‘‘):
    uId=input(‘User-Id: ‘)
#计数器
count=0

#读取第一页
index=0
url=url=url_1+uId+url_2+str(index)+url_3
html=getHtml(url)
(titleList,pubList,dateList,tagsList,commentList)=getBookComment(html)
htmlTitle=getHtmlTitle(html)
clearOldFile(uId);
fileName=saveBookComment(titleList,pubList,dateList,tagsList,commentList,uId)

count+=len(titleList)
try:
    pageNum=getPageNum(html)    #用户读过的书的网页页数
except:
    pageNum=1
index+=1
#读取后续页
for i in range(index*15,15*pageNum,15):
    print(‘Sleep for 5 seconds.‘)
    time.sleep(5)
    print(‘%d/%d‘ %(i/15+1,pageNum))
    url=url=url_1+uId+url_2+str(i)+url_3
    html=getHtml(url)
    (titleList,pubList,dateList,tagsList,commentList)=getBookComment(html)
    count+=len(titleList)
    saveBookComment(titleList,pubList,dateList,tagsList,commentList,uId)
print(‘\nMission accomplished!‘)
print(‘%d comments have been saved to %s.‘ %(count,fileName))
ans=input(‘\nDo you want to convert Markdown file to html file(Y/n)?‘)
ans=ans.lower()
if ans!=‘n‘:
    htmlName=convertMd2Html(fileName,htmlTitle)
    print(‘Convert success: %s‘ %htmlName)
os.system("pause") 
时间: 2024-11-05 13:35:20

[Python]豆瓣用户读书短评下载工具的相关文章

Windows安装Python包下载工具pip遇到的问题

到Python的官网下载get-pip.py文件,然后按照说明进行安装. 在安装过程中,我遇到以下问题: cmd的codepage引起的编码错误,提示65001编码错误,通过chcp 936切换到默认的代码页可解决此问题. 其次是权限的问题,运行cmd时已管理员权限启动即可. 最后安装完,需要将python目下的scritps目录添加到path环境下,方便直接使用pip命令. PS,不管遇到什么问题,一定记得根据提示看看错误日志,分析下原因,那么错误解决起来就很容易啦. Windows安装Pyt

Python 调用IDM下载工具下载链接文件

Python 调用IDM下载工具下载链接文件 IDM(Internet DownloadManager) 可以在Windows通过命令行参数启动,以及通过提供参数开始下载.需要添加大量下载链接时,使用脚本完成更为更为省时省力.下面为用 Python 调用IDM下载链接的两种方法. 使用os.system() import os def IDMdownload(DownUrl, DownPath, FileName): IDMPath = "C:\\Program Files (x86)\\Int

命令行视频下载工具you-get和youtube-dl

you-get和youtube-dl都是基于python的命令行媒体文件下载工具,完全开源免费跨平台.用户只需使用简单命令并提供在线视频的网页地址即可让程序自动进行嗅探.下载.合并.命名和清理,最终得到已经命名的完整视频文件.两者搭配使用几乎可以下载所有主流视频网站的视频及有关资源,配合本地播放器还可直接播放在线视频,彻底避免广告和浏览器插件的困扰. 在安装使用之前需要进行以下部署工作: 安装python3和pip 安装媒体处理工具FFmpeg you-get 官网:https://you-ge

python编程入门读书笔记1

python适合用来做什么呢? 脚本,这些简短的程序自动执行常见的管理任务,如在系统中新增用户.上传文件到网站.不使用浏览器浏览网页等. 网站开发,作为快速创建动态网站的工具,Django.bottle.Zope等python项目深受开发人员欢迎. 文本处理,python在字符串和文本文件处理方面提供了强大的支持,包括正则表达式和unicode. 科学计算,网上有很多卓越的python科学计算库,提供了统计.数学计算和绘图的函数. 教育,鉴于python的简洁实用,学校可以将其作为第一门编程语言

python之模块distutils,打包工具

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之模块distutils,打包工具 import distutils #distutils包有2个目的: 1)distutils希望让最终用户觉得安装新模块.包和工具的过程一致而轻松 2)distutils希望让新模块.包和工具的开发者觉得创建这些容易安装的分发包很轻松 总得来说,distutils就是用来打包的模块. #2.用distutils如何打包? #http://blog.csdn.

Fabric python的发布部署好帮手工具

Fabric是一个Python库和命令行工具,旨在为应用部署和系统管理任务的SSH的流水线式操作,使之更加高效和方便.Fabric提供了一套基本的执行本地和远程shell命令.上传和下载文件的操作,包括一些辅助函数,例如驱动正在运行的用户输入或者放弃执行. Fabric通过把大量频繁使用的SSH操作写入到一个脚本中(fabric.py),来远程执行一些应用部署或者系统维护的任务.Fabric是类似paramiko的一个库,是对paramiko的再次封装,所以比使用paramiko更简单. Fab

mysql创建和用户授权,可视化工具Navicat的基本使用,pymysql模块的使用

一.创建mysql,授权 权限管理 我们知道我们的最高权限管理者是root用户,它拥有着最高的权限操作.包括select.update.delete.update.grant等操作.那么一般情况在公司之后DBA工程师会创建一个用户和密码,让你去连接数据库的操作,并给当前的用户设置某个操作的权限(或者所有权限).那么这时就需要我们来简单了解一下: 如何创建用户和密码 给当前的用户授权 移除当前用户的权限 如果你想创建一个新的用户,则需要以下操作: 1.进入到mysql数据库下 mysql> use

python Linux 环境 (版本隔离工具)

python Linux 环境 (版本隔离工具) 首先新建用户,养成良好习惯useradd python 1.安装pyenv GitHub官网:https://github.com/pyenv/pyenv-installer pyenv installer This tool installs pyenv and friends. It is inspired by rbenv-installer. Prerequisites In general, compiling your own Pyt

15个最佳的用户体验和用户界面工具和资源

无论你是新手还是专业的网页设计师或者开发人员,你总是从创建线框开始来创建 Web 项目,而不是直接开发. 这不仅有助于让你保持在正确的轨道上,以免项目建成后出现了各种各样的问题. 目前有很多的工具和资源都能网上找到,使你的工作更容易.这里给大家推荐15个最佳的用户体验和用户界面工具和资源. 您可能感兴趣的相关文章 Web 前端开发人员和设计师必读精华文章推荐 精心挑选的优秀jQuery Ajax分页插件和教程 12个让人惊叹的的创意的 404 错误页面设计 让网站动起来!12款优秀的 jQuer