爬取泰山相关信息

一、实验目的

使用 Selenium + chromedriver模拟浏览器行为获取数据,但由于爬虫采集的原始数据往往会存在许多问题,例如数据格式不正确,数据存在缺失、冗余等等。因此第一手获得的原始数据不能直接使用,需要进行数据清洗。本案例对爬取的泰山相关信息数据进行处理,使其成为符合我们要求的数据。

二、实验内容

1. 爬取数据:

#爬取用户名,评分,评论日期,评论点赞数,评论正文
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lxml import etree
import pandas as pd
import time
import os
import re
from pymongo import *

#获取网页源代码
def get_page(page):
    wait = WebDriverWait(driver,10)
    #找到页码输入框
    search_box = driver.find_element_by_xpath('//li[@class="ant-pagination-options"]/div/input')
    #输入页码
    search_box.send_keys(page)
    #找到确定按钮
    search_btn = driver.find_element_by_xpath('//li[@class="ant-pagination-options"]/div/span/button')
    #找到某一位置
    logo = driver.find_element_by_xpath('//*[@id="__next"]/div[5]/div[1]/div[1]/div/h2')
    driver.execute_script("arguments[0].scrollIntoView(false);", logo)
    #点击确定按钮
    search_btn.click()
    time.sleep(5)
    return driver.page_source

# 利用XPath提取网页数据
def parse_page(html):
    dom = etree.HTML(html)
    #用户名
    name = dom.xpath('//div[@class="userName"]/text()')
    
    #评论日期
    date = dom.xpath('//div[@class="commentTime"]/text()')
    
    #评分,直接查找span节点,会多出1个值,因此找div下的即可
    score_list = dom.xpath('//div[@class="scroreInfo"]/span[@class="averageScore"]/text()')
    #取出数字:切片,每3个取一个
    score = score_list[::3]
    
    #评论点赞数
    #爬出的数字为实际点赞数,若爬出的是汉字‘点赞’则点赞数实际为0
    dz = dom.xpath('//span[@class="toolsItem"]/text()')

    #评论
    comment_org = dom.xpath('//div[@class="commentDetail"]/text()')
    #去掉换行符\n
    comment = [i.replace('\n','') for i in comment_org]
    
    #构建DataFrame
    data = pd.DataFrame({
        '用户名':name,
        '评分':score,
        '日期':date,
        '评论点赞数':dz,
        '评论正文':comment
        
    })
    return data

#每页数据以追加形式保存至csv文件
def save_file(filename, data): #参数为DataFrame
    if os.path.exists(filename):
        data.to_csv(filename,mode='a',encoding='utf_8_sig',index=False,header=False)
    else:
        data.to_csv(filename,mode='a',encoding='utf_8_sig',index=False) 

            
if __name__ == '__main__':
    filename = '爬取泰山相关信息(原始).csv'
    url = 'https://you.ctrip.com/sight/mounttai6/136014.html#ctm_ref=www_hp_bs_lst'
    driver = webdriver.Chrome()
    driver.get(url)
    driver.maximize_window()
    #获取指定的页面,避免评论时间太近
    for i in range(1,12):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(21,25):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(40,46):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(50,56):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(60,66):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(70,76):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(80,86):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(100,106):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(110,116):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    for i in range(120,126):
        html = get_page(i)
        data = parse_page(html)
        save_file(filename, data)
    print("OK!")
    
    driver.close()

2. 读取数据:

(1)导入数据集:爬取泰山相关信息(原始).csv

import pandas as pd
df1 = pd.read_csv(r'C:\此处省略具体路径\爬取泰山相关信息(原始).csv')
df1

在特定位置插入一列‘序号’

df1.insert(0,'序号',[i for i in range (1,631)])
df1

(2)显示前5条记录

df1.head()

3. 查看数据的整体情况

(1)查看数据的规模:行数和列数

#查看维度
print(df1.shape)

#获得行数
print(df1.index.size)
#print(df1.shape[0])

#获得列数
print(df1.columns.size)
#print(df1.shape[1])

(2)利用info()查看数据的维度、字段名及类型等

df1.info()

(3)利用describe()查看数据初步统计信息

df1.describe()

4. 数据清洗

(1)删除‘序号’列

del df1['序号']
df1

(2)重复值处理

查看是否存在重复行 

df1.duplicated()

查看重复行与非重复行的数量

cf = df1.duplicated()
cf.value_counts()

删除重复行(直接作用于原始数据)

df1.drop_duplicates(inplace=True)
df1

再次查看数据规模

df1.shape

(3)缺失值处理

查看各元素是否为空值

df1.isnull()

查看各列是否存在空值

#只要该列有空值,就为True
df1.isnull().any()

(4)某些值的替换

df1['评论点赞数'].replace('点赞',0,inplace=True)
df1

(5)异常值判断

a=0 #a用来统计异常值的数量
b=0 #b用来统计正常值的数量
for i in df1['评分']:
    if i not in range(6):
        a=a+1
    else:
        b=b+1
print("异常值的数量是 {} 个".format(a))
print("正常值的数量是 {} 个".format(b))


再看一下要保存的数据

df1

(6)将清洗完成的数据保存至“爬取泰山相关信息(新).xlsx”

df1.to_excel(r'C:\。。。\爬取泰山相关信息.xlsx',index=False,header=True)

5. 数据分析

(1)选出最有效的评论

#导入数据集
import pandas as pd
df2 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')

查看每一列的数据类型

df2.dtypes

将“点赞数”列转换为int类型

df2['评论点赞数'] = df2['评论点赞数'].astype('int')

取出最大点赞数的评论

#取点赞数最大值
df2['评论点赞数'].max()

#取点赞数最大值所在行
index = df2[df2["评论点赞数"] == 682].index.tolist()[0]
index

#取出点赞数最大值的一行数据并提取评论
yxpls = df2[df2.index==443]
yxpl = yxpls['评论正文']
yxpl

(2)查看评分的相关情况

#平均分
pjf = df2['评分'].mean()
print("平均分是{}".format(pjf))

#众数分
zsf = df2['评分'].mode()
print("众数是:{}".format(zsf))

fc = df2['评分'].var()
print("方差是:{}".format(fc))

(3)随机抽取10条数据查看数据情况

sj = df2.sample(10)
sj

#随机抽取数据的平均评分
sjpjf = sj['评分'].mean()
print("随机抽取数据的平均评分是 {} 分".format(sjpjf))

(4)绘制评论正文的词云

import pandas as pd
import jieba
from tkinter import _flatten
import matplotlib.pyplot as plt
import wordcloud

data1 = pd.read_excel(r'C:\.。。。\爬取泰山相关信息.xlsx')
comment = data1['评论正文']

#分词
comment_cut = comment.apply(jieba.lcut)
comment_last = [] #一维列表,存放分词结果
for i in comment_cut:
    for j in i:
        comment_last.append(j)
#或者用下述方法,将二维列表转为一维列表
#comment_last = list(_flatten(list(comment_cut)))

#统计词频,去除单个字符
counts = {}
for word in comment_last:
    if len(word) > 1:
        counts[word] = counts.get(word, 0) + 1
        
#显示词云 
pic = plt.imread(r'C:\。。。\leaf1.jpg') 
w = wordcloud.WordCloud(
    mask = pic, #背景图片
    background_color = 'white',#词云背景颜色
    font_path='C:/Windows/Fonts/simhei.TTF' #设置为中文字体,否则无法正常显示
)
w.fit_words(counts)#传入词频为字典类型,dic为上述字典
#w.generate_from_frequencies(counts)
plt.imshow(w) #转为plt图形数据
plt.axis('off')#取消显示x-y轴
plt.show()#展示图形
w.to_file(r'C:\。。。\泰山1.jpg')

(5)查看点赞数前10的评论正文,并绘制词云

将数据集按点赞数排序并取出前十名

data2 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')
w1 = data2.sort_values('评论点赞数',ascending=False).head(10)
w1

import pandas as pd
import jieba
from tkinter import _flatten
import matplotlib.pyplot as plt
import wordcloud

comment = w1['评论正文']

#分词
comment_cut = comment.apply(jieba.lcut)
comment_last = [] #一维列表,存放分词结果
for i in comment_cut:
    for j in i:
        comment_last.append(j)
#或者用下述方法,将二维列表转为一维列表
#comment_last = list(_flatten(list(comment_cut)))

#统计词频,去除单个字符
counts = {}
for word in comment_last:
    if len(word) > 1:
        counts[word] = counts.get(word, 0) + 1
        
#显示词云 
pic = plt.imread(r'C:\.。。。\leaf1.jpg')
w = wordcloud.WordCloud(
    mask = pic, #背景图片
    background_color = 'white',#词云背景颜色
    font_path='C:/Windows/Fonts/simhei.TTF' #设置为中文字体,否则无法正常显示
)
w.fit_words(counts)#传入词频为字典类型,dic为上述字典
#w.generate_from_frequencies(counts)
plt.imshow(w) #转为plt图形数据
plt.axis('off')#取消显示x-y轴
plt.show()#展示图形
w.to_file(r'C:\。。。\泰山2.jpg')

拓展查看点赞数前50的评论正文,并绘制词云

data2 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')
w2 = data2.sort_values('评论点赞数',ascending=False).head(50)
w2

import pandas as pd
import jieba
from tkinter import _flatten
import matplotlib.pyplot as plt
import wordcloud

comment = w2['评论正文']

#分词
comment_cut = comment.apply(jieba.lcut)
comment_last = [] #一维列表,存放分词结果
for i in comment_cut:
    for j in i:
        comment_last.append(j)
#或者用下述方法,将二维列表转为一维列表
#comment_last = list(_flatten(list(comment_cut)))

#统计词频,去除单个字符
counts = {}
for word in comment_last:
    if len(word) > 1:
        counts[word] = counts.get(word, 0) + 1
        
#显示词云 
pic = plt.imread(r'C:\。。。\leaf1.jpg')
w = wordcloud.WordCloud(
    mask = pic, #背景图片
    background_color = 'white',#词云背景颜色
    font_path='C:/Windows/Fonts/simhei.TTF' #设置为中文字体,否则无法正常显示
)
w.fit_words(counts)#传入词频为字典类型,dic为上述字典
#w.generate_from_frequencies(counts)
plt.imshow(w) #转为plt图形数据
plt.axis('off')#取消显示x-y轴
plt.show()#展示图形
w.to_file(r'C:\。。。\泰山3.jpg')

拓展查看点赞数后30的评论正文,并绘制词云

data2 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')
w3 = data2.sort_values('评论点赞数').head(30)
w3

import pandas as pd
import jieba
from tkinter import _flatten
import matplotlib.pyplot as plt
import wordcloud

comment = w3['评论正文']

#分词
comment_cut = comment.apply(jieba.lcut)
comment_last = [] #一维列表,存放分词结果
for i in comment_cut:
    for j in i:
        comment_last.append(j)
#或者用下述方法,将二维列表转为一维列表
#comment_last = list(_flatten(list(comment_cut)))

#统计词频,去除单个字符
counts = {}
for word in comment_last:
    if len(word) > 1:
        counts[word] = counts.get(word, 0) + 1
        
#显示词云 
pic = plt.imread(r'C:\.。。。\leaf1.jpg')
w = wordcloud.WordCloud(
    mask = pic, #背景图片
    background_color = 'white',#词云背景颜色
    font_path='C:/Windows/Fonts/simhei.TTF' #设置为中文字体,否则无法正常显示
)
w.fit_words(counts)#传入词频为字典类型,dic为上述字典
#w.generate_from_frequencies(counts)
plt.imshow(w) #转为plt图形数据
plt.axis('off')#取消显示x-y轴
plt.show()#展示图形
w.to_file(r'C:\。。。。\泰山4.jpg')

(6)统计各个评分对应的人数,并用饼图进行可视化展示

import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
#统计每个评分对应的人数,结果为Series类型:索引为评分,值为人数
num = data1['评分'].value_counts()
print(num)
plt.figure(figsize=(8,8)) #设置画布
plt.pie(num, labels=num.index, autopct = '%.2f%%')
#plt.axis("equal")
plt.title("不同评分对应人数饼图")
plt.savefig(r'C:\。。。\饼图1')#保存图片
plt.show()

(7)统计不同日期评分的数量及评分的平均值

dd = data1.groupby('日期')['评分'].agg(['count','mean'])
dd

(8)统计不同月份评分的数量及评分的平均值

导入数据集

import pandas as pd
df3 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')

进行相关处理

#取出日期中的月份
a=[]
for i in df3['日期']:
    a.append(i[5:7])
print(a)

#将月份插入到数据集中(位置指定)
df3.insert(2,'月份',a)
df3

#处理查看
ppp = df3.groupby('月份')['评分'].agg(['count','mean'])
ppp

#按评分的平均值进行排序
ttt = ppp.sort_values('mean',ascending=False)
ttt

#按count值进行排序
ttt2 = ppp.sort_values('count',ascending=False)
ttt2

#按评分的平均值,count值共同进行排序
ttt3 = ppp.sort_values(['mean','count'],ascending=False)
ttt3

(9)将评分与点赞数数据标准化

df3[['评分','评论点赞数']] = df3[['评分','评论点赞数']].apply(lambda x:(x-x.min())/(x.max()-x.min()))

df3.head()

df3.describe()

(10)将评分离散化并统计各等级的数量(优良差)

df4 = pd.read_excel(r'C:\。。。\爬取泰山相关信息.xlsx')

#数据类型的转化
df4['评分'] = df4['评分'].astype('int')

df4['评分'] = pd.cut(df4['评分'],bins=[0,3,4,5],labels=['差','良','好'], include_lowest=True)

df4

(11)将评分离散化后绘制饼图

import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
#统计每个评分对应的人数,结果为Series类型:索引为评分,值为人数
num = df4['评分'].value_counts()
print(num)
plt.figure(figsize=(8,8)) #设置画布
plt.pie(num, labels=num.index, autopct = '%.2f%%')
#plt.axis("equal")
plt.title("评分离散化后")
plt.savefig(r'C:\.。。。\饼图2')#保存图片
plt.show()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值