zoukankan      html  css  js  c++  java
  • Python小爬虫——抓取豆瓣电影Top250数据

    写LeetCode太累了,偶尔练习一下Python,写个小爬虫玩一玩~比较简单,抓取豆瓣电影Top250数据,并保存到txt、上传到数据库中。

    确定URL格式

    先找到豆瓣电影TOP250任意一页URL地址的格式,如第一页为:https://movie.douban.com/top250?start=0&filter=,分析该地址:

    • https:// 代表资源传输协议使用https协议;
    • movie.douban.com/top250 是豆瓣的二级域名,指向豆瓣服务器;
    • /top250 是服务器的某个资源;
    • start=0&filter= 是该URL的两个参数,分别代表开始位置和过滤条件。

    通过分析可以发现,不同页面之间是有start的值在变化,其他为固定部分。

    获取页面数据

    以面向对象的编码方式编写这个程序,养成好的编码习惯。

    基本信息在 (__init__) 函数中初始化。注意到其中有一个 (headers),这是用来做什么的呢?有一些网站有一点点反爬虫机制,对于一般的爬虫请求拒绝返回实际数据。一般来说,基本的反爬虫是通过判断发送请求中是否有浏览器的基本信息,因此,我们可以伪装成浏览器发送这些爬虫请求,通过修改http包中的heafer实现。

    问题又来了,这个User-Agent从哪来呢?你如果急着用,复制我的就可以用!如果想知道自己电脑浏览器的基本信息,可以搜索下载小程序“Fiddler”,打开程序后,打开一个网页,小程序就会获取发送的请求,其中就包含你要的东西。

    class MovieTop(object):
        def __init__(self):
            self.start = 0
            self.param = '&filter'
            self.headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64) "
                                           "AppleWebKit/537.36 (KHTML, like Gecko) "
                                           "Chrome/65.0.3325.146 Safari/537.36"}
            self.movieList = []
            self.filePath = './DoubanTop250.txt'
    
        def get_page(self):
            try:
                url = 'https://movie.douban.com/top250?start=' + str(self.start) + '&filter='
                myRequest = request.Request(url, headers=self.headers)
                response = request.urlopen(myRequest)
                page = response.read().decode('utf-8')
                print('正在获取第' + str((self.start+25)//25) + '页数据...')
                self.start += 25
                return page
            except request.URLError as e:
                if hasattr(e, 'reason'):
                    print('获取失败,失败原因:', e.reason)
    

    提取页面信息

    在上面的代码中,可以得到页面的代码,是HRML格式的文本,我们需要从中提取出有用的信息。在Chrome浏览器中,右键查看页面源代码可以看到稍微有格式的HTML文本,这和我们获取的page内容是相同的。找到其中的关键数据,如下:

    从中可以看到一条记录的页面代码结构,如何从中提取想要的信息呢?正则表达式匹配!还记得 (re模块) 中的 (compile)吗?

    这是比较麻烦的一件事,暂时先这样写,懂这行的都知道有一个东西叫做 (beautiful soup),它可以简洁易懂地提取页面信息,鉴于练习一下正则表达式,而且也比较简单,直接写出整个匹配式。下面是参考代码:

    还有一个小问题,本来想提取每条记录的全部信息,后来发现有的电影没有“别名”,还有的电影没有“主演”,不得不忽略这两条信息,最后每条记录只提取了10个信息。

        def get_page_info(self):
            patern = re.compile(u'<div.*?class="item">.*?'
                                + u'<div.*?class="pic">.*?'
                                + u'<em.*?class="">(.*?)</em>.*?'
                                + u'<div.*?class="info">.*?'
                                + u'<span.*?class="title">(.*?)</span>.*?'
                                + u'<span.*?class="other">(.*?)</span>.*?'
                                + u'<div.*?class="bd">.*?'
                                + u'<p.*?class="">.*?'
                                + u'导演:s(.*?)s.*?<br>'
                                + u'(.*?)&nbsp;/&nbsp;'
                                + u'(.*?)&nbsp;/&nbsp;(.*?)</p>.*?'
                                + u'<div.*?class="star">.*?'
                                + u'<span.*?class="rating_num".*?property="v:average">'
                                + u'(.*?)</span>.*?'
                                + u'<span>(.*?)人评价</span>.*?'
                                + u'<span.*?class="inq">(.*?)</span>'
                                , re.S)
    
            while self.start <= 225:
                page = self.get_page()
                movies = re.findall(patern, page)
                for movie in movies:
                    self.movieList.append([movie[0],
                                           movie[1],
                                           movie[2].lstrip('&nbsp;/&nbsp;'),
                                           movie[3],
                                           movie[4].lstrip(),
                                           movie[5],
                                           movie[6].rstrip(),
                                           movie[7],
                                           movie[8],
                                           movie[9]])
    

    写入TXT文件

    这个就比较简单了,直接进行文件操作,将其写入txt即可。

        def write_page(self):
            print('开始写入文件...')
            file = open(self.filePath, 'w', encoding='utf-8')
            try:
                for movie in self.movieList:
                    file.write('电影排名:' + movie[0] + '
    ')
                    file.write('电影名称:' + movie[1] + '
    ')
                    file.write('电影别名:' + movie[2] + '
    ')
                    file.write('导演:' + movie[3] + '
    ')
                    file.write('上映年份:' + movie[4] + '
    ')
                    file.write('制作国家/地区:' + movie[5] + '
    ')
                    file.write('电影类别:' + movie[6] + '
    ')
                    file.write('评分:' + movie[7] + '
    ')
                    file.write('参评人数:' + movie[8] + '
    ')
                    file.write('简短影评:' + movie[9] + '
    ')
                    file.write('
    ')
                print('成功写入文件...')
            except Exception as e:
                print(e)
            finally:
                file.close()
    

    上传至数据库

    作为实验,先在本地mysql数据库中建立PythonTest数据库,创建doubanTop250表,就不在python代码中创建了。注意字符集设为 (utf8),不然可能出现1366错误。

    CREATE DATABASE PythonTest;
    
    CREATE TABLE doubanTop250(
        ID int PRIMARY KEY AUTO_INCREMENT,
        rank int,
        name varchar(50),
        alias varchar(100),
        director varchar(50),
        showYear varchar(50),
        makeCountry varchar(50),
        movieType varchar(50),
        movieScore float,
        scoreNum int,
        shortFilm varchar(255)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    接下来在Python代码中添加一个函数,将数据导入数据库。

        def upload(self):
            db = pymysql.connect("localhost", "root", "love1125", "PythonTest", charset='utf8')
            cursor = db.cursor()
    
            insertStr = "INSERT INTO doubanTop250(rank, name, alias, director," 
                        "showYear, makeCountry, movieType, movieScore, scoreNum, shortFilm)" 
                        "VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', %f, %d, '%s')"
    
            try:
                for movie in self.movieList:
                    insertSQL = insertStr % (int(movie[0]), str(movie[1]), str(movie[2]), str(movie[3]),
                                             str(movie[4]), str(movie[5]), str(movie[6]), float(movie[7]),
                                             int(movie[8]), str(movie[9]))
                    cursor.execute(insertSQL)
                db.commit()
                print('成功上传至数据库...')
            except Exception as e:
                print(e)
                db.rollback()
            finally:
                db.close()
    

    完整代码:https://github.com/Pacsiy/learnPY

    本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

  • 相关阅读:
    UVALive2678子序列
    UVA11549计算机谜题
    UVA11520填充正方形
    LA3635派
    UVALive3971组装电脑
    记录未完成题目
    SPOJ 6219 Edit distance字符串间编辑距离
    ACM组队安排-——杭电校赛(递推)
    逆袭指数-——杭电校赛(dfs)
    油菜花王国——杭电校赛(并查集)
  • 原文地址:https://www.cnblogs.com/AlvinZH/p/8576841.html
Copyright © 2011-2022 走看看