文章目录

  • 前言
  • 关于项目
  • 博客结构
  • 项目简介
  • 用到的库
  • 自己的工具类
  • 相关配置
  • 效果展示
  • 过程简述
  • 全局变量
  • main方法
  • get_id方法
  • get_comments方法
  • 步骤详解
  • 获取主键
  • 请求阶段
  • 解析阶段
  • 异常处理
  • 获得评论
  • 请求阶段
  • 解析阶段
  • 异常处理


前言

关于项目

前段时间看到各种年度热词统计出来的时候,自己也想做一下词语的统计,在此就爬取了豆瓣短评,生成了词云以及条形图;项目已经放在GitHub上 https://github.com/JiajunBernoulli/douban-short-commentary ,感兴趣的朋友可以通过修改配置文件实现其他电影的短评爬取及绘图。

博客结构

过程简述中将主要的代码,分函数呈现出来,已经熟悉我所用技术的可以不看之后的步骤详解,不太熟悉的朋友在看过程简述看不明白的地方可以通过目录定位到步骤详解的细节,文档尾部的注释也建议新手注意一下。

项目简介

用到的库

import time
from selenium.webdriver.support import expected_conditions as EC
from urllib.parse import urlparse
from selenium import webdriver
from pyquery import PyQuery as pq
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait

selenium1用于请求
pyquery2用于解析

自己的工具类

from config import *
from utils.cut_sentences import get_ord_words, get_words		## 对jieba分词操作的封装
from utils.draw_pic import draw_wordCloud, draw_bar				## 对matplotlib操作进行的封装
from utils.gene_echarts import gene_wordCloud					## 生成echarts文件
from utils.save_mongo import save_to_mongo						## 对MongoDB操作封装的工具类

相关配置

## 指定想搜索的豆瓣电影以及想爬取的最大评论数与前TOP的排名
KEYWORD = '地球最后的夜晚'
MAX_COUNT = 20
TOP_NUM = 10

## 指定想要忽略的词
IGNORE = [“电影”]

## 指定python绘制词云的字体路径、图片路径以及保存路径
FONT_PATH = 'resources/SimHei.ttf'
PIC_PATH = 'resources/timg.jpg'
FILE_PATH = 'results/地球最后的夜晚.jpg'

## 指定MongoDB相关配置
MONGO_URL = 'localhost'
MONGO_DB = 'lastnight'
MONGO_TABLE_COMMENTS = 'comments'
MONGO_TABLE_WORDS = 'words'

## 指定生成echarts文件的相关参数
WORD_CLOUD_NAME = 'results/地球最后的夜晚.html'
WORD_CLOUD_TITLE = '地球最后的夜晚'

效果展示

python绘制的前十词云

python 同义词模型 python的词语_爬虫


python绘制的柱状图

python 同义词模型 python的词语_html_02

过程简述

我的思路是先登录官网,搜索关键词获得电影的主键,再通过主键爬取短评的页面,然后存储、绘图。
请求用的是slenium

全局变量

browser = webdriver.Chrome()
wait = WebDriverWait(browser, 10)            ##  设置浏览器超时时间

main方法

def main():
    ## 请求网页并解析
    browser.get('https://movie.douban.com/')
    id = get_id(KEYWORD)
    comments = get_comments(id, MAX_COUNT)
    browser.close()
    ## 构造记录存入MongoDB
    for comment in comments:
        save_to_mongo(MONGO_TABLE_COMMENTS,{'comment': str(comment)})
    ## 获得排名前10的词语
    ord_list, names, values = get_ord_words(comments, TOP_NUM)
    ## 构造记录存入MongoDB
    for i in range(0, len(ord_list)):
        save_to_mongo(MONGO_TABLE_WORDS, {'NUM': i+1, 'NAME': ord_list[i][0], 'VALUE': ord_list[i][1]})
    ## 利用自己的绘图工具类进行绘图
    draw_wordCloud(get_words(comments))
    draw_bar(names, values)
    ## 利用自己的工具类生成echarts文件
    gene_wordCloud(WORD_CLOUD_NAME, WORD_CLOUD_TITLE, names, values)

get_id方法

def get_id(keyword):
    try:
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#inp-query'))
        )
        input.send_keys(keyword)
        time.sleep(0.5)
        input.send_keys(Keys.DOWN)
        input.send_keys(Keys.ENTER)
        time.sleep(0.5)
        url = browser.current_url
        result = urlparse(url)
        id = re.findall('\d+', result.path)
        return id[0]
    except TimeoutException:
        return get_id(keyword)

get_comments方法

comments = [] 
    for count in range(0, maxcount, 20):
        url = "https://movie.douban.com/subject/"+str(id)+"/comments?start="+str(count)+"&limit=20&sort=new_score&status=P"
        print(url)
        try:
            browser.get(url)
            wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '#comments > div:nth-child(20) > div.comment > p > span'))
            )
            # with open("resources/comments.html", encoding="utf-8") as f: # 利用本地的html解析进行之后的测试,减少请求次数
            #     content = f.read()
            # doc = pq(content)
            html = browser.page_source
            doc = pq(html)
            items = doc.find('.short').items()
            for item in items:
                comments.append(item.text())
        except TimeoutException:
            print(str(count)+"超时")
            continue
    return comments

步骤详解

获取主键

在这一步中,通过搜索电影来获得电影的主键。

请求阶段

#################### 通过关键词获得id###################
def get_id(keyword):
    try:
        ## 等待输入框加载出来
        input = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#inp-query'))
        )
        ## 输入关键词
        input.send_keys(keyword)
        ## 关键是等待下拉菜单出来,sleep时间可调整
        time.sleep(0.5)
        ## 通过模拟键盘按键选中下拉菜单的第一个电影并跳转
        input.send_keys(Keys.DOWN)
        input.send_keys(Keys.ENTER)
        time.sleep(0.5)
        ## 得到跳转后的url并解析从而获得id
        url = browser.current_url

解析阶段

这里需要用到两个模块

from urllib.parse import urlparse
import re

前者用于url的解析,后者用于正则提取出主键

result = urlparse(url)
        id = re.findall('\d+', result.path)
        return id[0]

异常处理

except TimeoutException:
        ## 请求超时则重新请求
        return get_id(keyword)

获得评论

通过获得的主键,进入短评页面爬取。

请求阶段

def get_comments(id, maxcount):
    comments = []   ## 用于存储爬取出来的评论
    for count in range(0, maxcount, 20):
        url = "https://movie.douban.com/subject/"+str(id)+"/comments?start="+str(count)+"&limit=20&sort=new_score&status=P"
        print(url)
        try:
            browser.get(url)
            ## 等待最后一条短评加载出来
            wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '#comments > div:nth-child(20) > div.comment > p > span'))
            )
            # with open("resources/comments.html", encoding="utf-8") as f: # 利用本地的html解析进行之后的测试,减少请求次数
            #     content = f.read()
            # doc = pq(content)
            ## 获取源码用pyquery解析
            html = browser.page_source

当中注释的部分是我存了一部分html的代码,便于解析时候的调试

解析阶段

doc = pq(html)
            items = doc.find('.short').items()
            ## 取出标签中的文字存入评论列表
            for item in items:
                comments.append(item.text())

在这里我是用pyquery进行的解析

异常处理

except TimeoutException:
            ## 请求超时放弃此页,请求下一页
            print(str(count)+"超时")
            continue
    return comments

  1. 一个能调用谷歌、火狐等主流浏览器的库,需要注意版本与浏览器的匹配。 ↩︎
  2. 一个类似于jquery的解析库,用CSS选择器可方便爬取出页面中的元素。 ↩︎