前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【菜鸟致敬】爬取豆瓣的短评(⊙o⊙)…

【菜鸟致敬】爬取豆瓣的短评(⊙o⊙)…

作者头像
福贵
发布2018-07-25 10:48:33
9760
发布2018-07-25 10:48:33
举报
文章被收录于专栏:菜鸟致敬菜鸟致敬

提示,颜色不同是因为不是同一个时候写的,这个时候写的就选绿色吧,比较好看

因为需要一点数据,所以就去爬取一点豆瓣短评的数据。因为短评页面是生成的静态html,还是很容易爬虫数据的,其中发现了问题每部电影短评在同一条件下最多只能查阅500条,即使你已经登录豆瓣,当然,如果你没有登录只能查看前面的200条短评。

其实到这里我本着不造轮子的想法,找到了网上大佬写的代码,以为copy一下就可以了,然额事情并没有你想象中的那么简单。贴一下其中一份代码,吐槽的事情交给你们。(终于知道了加上代码风格的片段的办法了

代码语言:javascript
复制
import requests  
import re 
import pandas as  
 
pdurl_first='https://movie.douban.com/subject/26363254/comments?start=0' 
head={'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/59.0.3071.109 Chrome/59.0.3071.109 Safari/537.36'} 
html=requests.get(url_first,headers=head,cookies=cookies) 
 
cookies={'cookie':'你自己的cookie'}  #也就是找到你的账号对应的cookie 
 
reg=re.compile(r'<a href="(.*?)&amp;.*?class="next">') #下一页 
 
ren=re.compile(r'<span class="votes">(.*?)</span>.*?comment">(.*?)</a>.*?</span>.*?<span.*?class="">(.*?)</a>.*?<span>(.*?)</span>.*?title="(.*?)"></span>.*?title="(.*?)">.*?class=""> (.*?)\n',re.S)  #评论等内容 
 
while html.status_code==200: 
 url_next='https://movie.douban.com/subject/26363254/comments'+re.findall(reg,html.text)[0]                              
zhanlang=re.findall(ren,html.text) 
data=pd.DataFrame(zhanlang) 
data.to_csv('/home/wajuejiprince/文档/zhanlang/zhanlangpinglun.csv', header=False,index=False,mode='a+') #写入csv文件,'a+'是追加模式 
data=[] 
zhanlang=[] 
html=requests.get(url_next,cookies=cookies,headers=head)

其实看到第三行就感觉怪怪的,但考虑到我是弱鸡,毕竟Python语法是我在不停报错中外加看demo中自己熟悉的吧,可能这是一种高级的用法。

运行一下,报错实在太多,只能看一下源码啊,看不懂,无奈放弃,只能自己造轮子。

自己看了看链接样式和短评的样式,开始自己造轮子,当然这个时候我还没意识到豆瓣短评最多只能爬取500条了。

开始的时候选择了requests+re大法,一切很OK。稍微不好的一点就是因为正则表达式涉及换行的匹配,很容易将多的内容匹配进来

好滴,楼上图太丑,再放一张

短评是这样的,正则是这样的,考虑到自己弱鸡,无奈换一个思路,xpath没看过,只能BeautifulSoup。一切很ok,下面是正则变表达式,有前辈指点一下就更好了。

代码语言:javascript
复制
<p class="">((.|\n)*?)</p>

当然这是在计科的师兄支援下,改进了一下自己的轮子,放代码(湄公河)。代码是能够正常操作了,稍微改进一下就是一个可以滚的轮子了,其他电影的短评也可以拿到了。代码我会继续改进,毕竟我写的东西一般从v1.0到v1.9才会截止。

代码语言:javascript
复制
# 不知道什么原因,导入不了同文件夹模块,所以集合在一个py文件里面
import requests
import pymysql
from bs4 import BeautifulSoup

conn = pymysql.connect(host='127.0.0.1', user="root", passwd='0823', charset='utf8')
cursor = conn.cursor()
cursor.execute('use yingping;')
cursor.execute('drop table if exists mgh;')
cursor.execute('create table if not exists mgh (pinglun text);')
mgh_head = 'https://movie.douban.com/subject/25815034/comments?start='
mgh_tail = '&limit=20&sort=new_score&status=P&percent_type='

header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'
}
cookie = {
    'Cookie': 'll="118281"; bid=kcwGKisJCzs; __yadk_uid=u3uHskig8KBwzvtU043Bvda3sLkYN4jO; ps=y; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1524753458%2C%22https%3A%2F%2Fwww.douban.com%2F%22%5D; __utmt=1; _vwo_uuid_v2=D0B59412967E6C51F8AC6A90E8A9CE669|c5179d30bf2a1df782b34129bf7f0af2; as="https://movie.douban.com/subject/25815034/comments?start=320&limit=20&sort=new_score&status=P&percent_type="; dbcl2="152650172:7EdGrc9pqS4"; ck=WIUd; ap=1; __utma=30149280.853980687.1524740480.1524746415.1524753459.3; __utmb=30149280.2.10.1524753459; __utmc=30149280; __utmz=30149280.1524740480.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1616095102.1524740480.1524746415.1524753459.3; __utmb=223695111.0.10.1524753459; __utmc=223695111; __utmz=223695111.1524740480.1.1.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_id.100001.4cf6=87b9b010fb017976.1524740481.4.1524753790.1524751409.; _pk_ses.100001.4cf6=*; push_noty_num=0; push_doumail_num=0'
}
mgh_urls = []
# regex = re.compile('<p class="">((.|\n)*?)</p>')
for i in range(0, 1000, 20):
    mgh_urls.append(mgh_head + str(i) + mgh_tail)
#
# for url in mgh_urls:
#     print(url)
for i, mgh_url in zip(range(0, 50), mgh_urls):
    mgh_resp = requests.get(url=mgh_url, cookies=cookie)
    mgh_resp.encoding = 'utf-8'
    soup = BeautifulSoup(mgh_resp.text,'lxml')
    mgh_result = soup.find_all(name='p')

    for i in range(3,23):
        print(mgh_result[i].string)
    # mgh_result = regex.findall(mgh_resp.text)
    # print(mgh_result)
    #     with open('mgh.txt', mode='w', encoding='utf-8') as f:
   #                    for it in mgh_result:
    #         f.write(str(mgh_result[i].string))
    #     f.close()

        try:
            cursor.execute("insert into mgh(pinglun) values(%s);",str(mgh_result[i].string))
        except:
            conn.commit()
            conn.close()
conn.commit()
conn.close()

为什么没有考虑到class属性,是因为它的class为空值,对最后结果没有影响。

考虑到速度,所以选择了lxml解析器(

多线程不太会用)。当然豆瓣不反爬,也就没有设置代理。

不过很遗憾,利用cookie模拟登陆失败了(虽然我看了每次的cookie值是一模一样的,可能少了啥东西吧,利用的是最上面的代码的模拟登陆的思路),导致每次只能爬到200条有效信息。

Python看的脑阔疼。

经过俩天的版本(这篇俩天前开始写,之后没动过了),终于有了一个比较好的版本,不说了,直接放代码

代码语言:javascript
复制
# 不知道什么原因,导入不了,所以集合在一个py文件里面
import time
import requests
import csv
from bs4 import BeautifulSoup
head = 'https://movie.douban.com/subject/'
middle = '/comments?start='
zr_tail = '&limit=20&sort=new_score&status=P&percent_type='
names = []
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'
}

zr_urls = ['最热']
def createUrls():
    for j in range(1, 34, 2):
        name = names[j]
        for i in range(0, 100, 20):
            # if i < 100:
            zr_urls.append(head + str(name) + middle + str(i) + zr_tail)  # 构建最热默认
    

def readName():
    with open('编号.txt', mode='r', encoding='utf-8') as f:
        for i in f.readlines():
            i = i.strip('\n')
            names.append(i)
        # print(names)
def get_comments(urls):
    global sort_name  #
    sort_name = urls[0]  # 从第一个元素得到分类方式
    del urls[0]  # 删掉
    for url in urls:
        comment_list = []
        try:
            resp = requests.get(url=url, headers=header)
            time.sleep(5)  # 亲测大概4000条数据被封ip,这样的话不会封ip
            print('正在请求 ' + url)
            if resp.status_code != 200:
                print("啊哈哈哈,ip又被封了,等一会我们再来")
                time.sleep(5)
                resp = requests.get(url=url, headers=header)
        except:
            continue
        resp.encoding = 'utf-8'  # 使用utf-8编码
        # print(resp.text)
        soup = BeautifulSoup(resp.text, 'lxml')
        global video_name
        video_name = soup.find(name='title').string
        print(video_name)
        global result
        result = soup.find_all(name='p')  # 所有的评论
        for item in result[2:22]:
            comment_list.append(item.get_text())  # 找到所有p标签下的文本,不迭代
        # print(len(result))  # 打印长度,用于debug
        if urls.index(url) % 5 == 0:
            with open(video_name + sort_name + '.csv', mode='w',
                      encoding='utf-8') as f:  # 使用utf-8格式编码,直接打开csv文件会乱码,需要指定编码
                f.write(video_name + "\n")
                f.close()
        with open(video_name + sort_name + '.csv', mode='a', encoding='utf-8') as f:
            write = csv.writer(f)
            write.writerow(comment_list)
            f.close()
            print("完成了" + video_name + "这一页,咋们继续!")
            print("--------------------")
readName()
createUrls()
get_comments(zr_urls)

菜鸟级代码,大概还会改进的地方:①写一个抓取豆瓣影评对应id的接口(编号.txt文件请在后台发送 编号 获取)②使用mysql存储爬到的短评(存取txt,csv和mysql的函数实际已经写好)③使用多线程

备注:去掉请求后面的睡眠,大概会在200个页面后被封ip,当天会被列入黑名单,之后请求一旦过快就会被立刻封ip。

因为代码是我一个人码的,所以很随意,毕竟自己能看懂的代码才是好代码。

本文适合入门级菜鸟程序猿。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python与MySQL 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档