学了爬虫之后,都只是爬取一些简单的小页面,觉得没意思,所以我现在准备爬取一下豆瓣上张艺谋导演的“影”的短评,存入数据库,并进行简单的分析和数据可视化,因为用到的只是比较多,所以写一篇博客当做笔记。
第一步:想要存入数据库就必须与数据库进行链接,并建立相应的数据表,这里我是在win10下使用oracle数据库。
经过思考,我认为我们爬取一个短评的时候,只需要用到几个字段:
1.用户名
2.评论的日期
3.这个评论有多少人点赞
4.这个用户给电影打几分
5.用户的评价
接下来写一个函数,这个函数的功能是:根据传入的参数来判断在指定用户下是否存在指定的表,如果存在,就先删除表,再创建表,如果不存在,就直接创建表。这样做可以保证你创建表的时候不会报错,因为函数会根据传入的参数进行建表,代码如下
import cx_Oracle #导入连接oracle需要的包 def begin(table_name): #参数是你要创建的表的名称 db = cx_Oracle.connect('scott/tiger@localhost:1521/mldn') #连接数据库scott是用户名,tiger是密码,@localhost:1521/mldn是监听,根据自己实际情况来填写 cr = db.cursor() #创建sursor drop_sql="drop table " + table_name #这个sql语句是删除表 gudge_sql = "SELECT COUNT(*) FROM ALL_TABLES WHERE OWNER = UPPER('scott') AND TABLE_NAME = UPPER('"+ table_name +"')" #这个sql语句是判断在scott用户下下是否存在table_name表,不存在,则返回值为0 s = "(name varchar2(50),comment_date varchar2(50),vote varchar2(40),star varchar2(40),user_comment varchar2(3000))" create_sql = "create table " + table_name + s #这是创建表的sql语句 cr.execute(gudge_sql) #查询table_name表是否存在 rs = cr.fetchall() #接收返回值 t = str(rs)[2:-3] #把返回值转化为字符串 if t not in [ '0',]: #如果返回值不为零,即table_name表存在 cr.execute(drop_sql) # 执行删除语句 cr.execute(create_sql) #创建table_name表 db.close() #关闭数据库连接
这个函数根据你传入的表名来创建数据表
第二步:构造请求头
现在有了数据表,你以为可以开始编写爬了?并不能,经过我实践,发现如果以游客身份爬取,爬不了多少数据,需要登录后才可以爬取更多的数据,我不想去爬虫来模拟登录,第一,太繁琐,第二,因为有图片验证码,目前我还不会用算法来自动识别图片。所以我的方法是:首先用浏览器人工登陆一次,然后按下F12或者Fn+F12,选中Network,刷新一下页面,在Name栏选中最顶上的一项点击,就会如下图所示,
把这个Request Headers下的内容复制下来,做成一个字典,再装载成请求头,就可以爬取所有数据了
设置headers的代码如下:
from urllib import request def set_hesders(url): ''' 设置请求头 :param url: url链接 :return: 装载后的url链接 ''' heraders = { 'Accep': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Connection': 'keep-alive', 'Cookie': 'll="108310"; bid=DPJxH93sKZk; ps=y; push_noty_num=0; push_doumail_num=0; __utmz=30149280.1539566865.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmv=30149280.18590; _ga=GA1.2.1546841640.1539566865; _gid=GA1.2.971937718.1539566892; __utmz=223695111.1539567345.1.1.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __yadk_uid=9XHtMuB2idRYlXP8XsRsmPElvO1oUwKN; _vwo_uuid_v2=DDCDE0957ED07334B61B397CFEF020CDF|2e3c5addb3d627db5895e452f22fa302; gr_user_id=a617c8a3-166c-4cd2-960e-381f28945fb6; ap_v=0,6.0; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1539599000%2C%22https%3A%2F%2Fwww.douban.com%2F%22%5D; _pk_ses.100001.4cf6=*; __utma=30149280.1546841640.1539566865.1539588868.1539599000.4; __utma=223695111.1546841640.1539566865.1539588868.1539599001.4; __utmb=223695111.0.10.1539599001; ue="3203655760@qq.com"; __utmc=30149280; __utmt=1; dbcl2="185909990:9qcuJLLcZVo"; ck=HKvy; __utmb=30149280.4.10.1539599000; __utmc=223695111; _pk_id.100001.4cf6=39d7c14ac0d6bd63.1539567345.4.1539600176.1539589195.', 'Host': 'movie.douban.com', 'Referer': 'https://movie.douban.com/', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3' } return request.Request(url,headers = heraders)
第三步:生成url
通过观察,我们知道,在影评的每一页的url链接都差不多,所以用一个函数来生成每一页的url
代码如下:
def get_pageurl(): pageurl_list = [] for i in range(25): url = "https://movie.douban.com/subject/4864908/comments?start=" + str(i * 20) + "&limit=20&sort=new_score&status=P" pageurl_list.append(url) return pageurl_list
第四步:爬取页面并解析页面,运用xpath解析,然后把数据存入数据库
此过程需要用到sqlalchemy库、pandas库
from sqlalchemy import create_engine from urllib import request from lxml import etree import pandas as pd import os os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' #我这行代码是因为我向数据库写入或者读取时有中文会报错,所以才写这行代码 def spyder_and_insert(table_name,url): engjine = create_engine('oracle://scott:tiger@localhost:1521/mldn') url = set_hesders(url) try: rsp = request.urlopen(url) #url请求 except: print("url错误") html = rsp.read() html = etree.HTML(html) try: comment_List = html.xpath("//div[@class='comment']") except: print("cookie错误") for i in range(len(comment_List)): name = str(comment_List[i].xpath("./h3/span[@class = 'comment-info']/a/text()"))[2:-2] comment_date = str(comment_List[i].xpath("./h3/span[@class = 'comment-info']/span[@class='comment-time ']/text()"))[24:-20] vote = str(comment_List[i].xpath("./h3/span[@class='comment-vote']/span/text()"))[2:-2] star = str(comment_List[i].xpath("./h3/span[@class = 'comment-info']/span[last()-1]/@title"))[2:-2] user_comment = str(comment_List[i].xpath("./p/span/text()"))[2:-2] if star not in ['很差','还行','较差','力荐','推荐']: star = "未打分" d = [{"comment_date": comment_date, "name": name, "vote": vote, "star": star, "user_comment": user_comment},] df = pd.DataFrame(d) #转化为DataFrame类型 try: #向数据库写入数据 df.to_sql("douban_comments", con=engjine, index=False, if_exists="append") except: print("向数据库插入数据出错")
第五步:爬取所有评论并存入数据库,为了更直观的查看爬虫爬取的进度,我编写了一个进度条代码,效果如下
函数的代码如下:
def gather(): print("开始爬取".center(30, "-")) start = time.perf_counter() print(" 0 %[->************************.]0.45s",end="") table_name = "douban_comments" user_name = "scott" begin(user_name, table_name) douban_pageurls = get_pageurl() lo = len(douban_pageurls) for i in range(lo): spyder_and_insert(table_name,douban_pageurls[i]) a = '*' * i b = '.' * (lo - i) c = (i / lo) * 100 dur = time.perf_counter() - start print("\r{:^3.0f}%[{}->{}]{:.2f}s".format(c, a, b, dur), end='') time.sleep(0.1) print("\n" + "爬取结束".center(30, '-'))
现在数据已经存入数据库了,现在我们用代码对数据进行简单分析,使数据可视化
该过程会用到numpy库、matplotlib库,
首先,我们对评价进行统计,分别画出直方图和饼状图,代码如下
from sqlalchemy import create_engine import cx_Oracle import pandas as pd import numpy as np import os import matplotlib.pyplot as plt os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' engjine = create_engine('oracle://scott:tiger@localhost:1521/mldn') def begin(): aaa = pd.read_sql_table("douban_comments",con=engjine) s1 = aaa.loc[aaa["star"]=="很差",["star"]].count()["star"] s2 = aaa.loc[aaa["star"]=="较差",["star"]].count()["star"] s3 = aaa.loc[aaa["star"]=="还行",["star"]].count()["star"] s4 = aaa.loc[aaa["star"]=="推荐",["star"]].count()["star"] s5 = aaa.loc[aaa["star"]=="力荐",["star"]].count()["star"] s6 = aaa.loc[aaa["star"]=="未打分",["star"]].count()["star"] a = np.array([s1,s2,s3,s4,s5,s6]) b = np.array(["一星","两星","三星","四星","五星","未打分"]) plt.rcParams['font.sans-serif'] = 'SimHei' plt.rcParams['axes.unicode_minus'] = False return a,b def zhifangtu(a,b): plt.bar(b,a,width = 0.8) plt.title("“影”的评分") #plt.show() plt.savefig('./ying1.png',dpi=200) def bingzhuangtu(a,b): plt.figure(figsize=(6, 6)) plt.pie(a, labels=b, autopct='%1.1f%%') plt.title("“影”的评分") plt.savefig('./ying2.png', dpi=200)
运行函数后,得到下面两幅图:
还可以对评论进行统计,这里我用jieba库和wordcloud库来对所有评论进行中文分词并生成词云
代码如下:
import jieba from sqlalchemy import create_engine import pandas as pd import numpy as np import os import re import wordcloud def ciying(): os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' engjine = create_engine('oracle://scott:tiger@localhost:1521/mldn') aaa = pd.read_sql_table("douban_comments",con=engjine) a = "" for i in range(len(aaa['user_comment'])): #循环取出所有评论并拼接字符串 a += str(aaa.loc[i,'user_comment']) ls = jieba.lcut(a) #用jieba库分词 txt = " ".join(ls) w = wordcloud.WordCloud( width=1000, height=700, background_color="white", font_path="msyh.ttc" ) w.generate(txt) #生成词云 w.to_file("ying3.png") #保存图片 ciying()
运行函数后的图片如下:
通过上面几个图面,我们发现其实评价也还好,打三分四分的占了近60%,毕竟可是从豆瓣爬取的评论,豆瓣大家都懂的。。。
总结:因为涉及到的知识点比较杂,所以我就想着写篇博客,当作自己的学习笔记了,我的代码还有许多写的差的的地方,函数命名也不专业,但是这是我第一个把数据写入数据库的爬虫,自己心里还是有点小激动的....