美文网首页python爬虫程序编码
Python爬虫之爬豆瓣电影数据

Python爬虫之爬豆瓣电影数据

作者: 逝我 | 来源:发表于2017-04-30 13:48 被阅读754次

    0x000 前言

    最近和公司的IOS谈起,以前我们是做移动端,现在已经和前端混为一谈了。 也是 , 做了一年多的Android ,一直都是在写界面展示数据,写交互 ,存储简单的数据 ,最主要的业务数据与业务逻辑都在服务器端,这让我有种离了服务端,我们只能玩玩单机和联机了 。作为曾经的web开发,深知服务端的重要性,我们要想做一款好的产品,没有服务端是万万不能的 , 而我们做移动端的更是要知晓一些服务端的知识 。

    我有一个梦想,做一款属于自己的产品 ,但苦于没有足够的数据,于是就开始了我的Python爬虫之旅 。(如果有时间,我会写如何从零收集数据-->服务器端的建立 --> 客户端的编写 , 一整套教程)

    0x001 Python基础

    Python是一门很简洁的语言 , 因为市面上介绍Python语法的教程很多 , 大多数都很好 ,我这里就不啰嗦了 , 下面贴出我看过的网站:

    廖雪峰 - Python教程
    简明Python教程

    0x002 网络爬虫

    网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。[来自百度]

    我们通过URL让爬虫来爬取我们想要的内容 , 根据我们的规则进行深入爬取 , 比如说 , 我们想要爬取正在上映的电影数据 , 并下载电影海报,其他的内容我们忽略掉,那么我们就需要根据网页内容的规则来制订,哪些内容是我们需要的,哪些是我们不需要的。

    0x003 爬取豆瓣电影数据

    第一步 : 打开豆瓣电影 , 分析网页结构

    我们爬取的网址是 https://movie.douban.com/cinema/nowplaying/shenzhen/ ,里面有一个的模块叫正在上映 , 我们就解析这个模块,其他的内容我们忽略掉。chrome(firefox)按f12查看网页结构。

    网页结构

    我们可以用元素选择工具,选中我们要分析的数据,firebug控制台就会将选中html结构展示出来。我们通过分析 , 我们想要的数据是在一个ul标签里面,每一个li标签就是一部电影的数据,我们只需要取出里面的li中的数据即可。豆瓣的前台使用了数据绑定的技术 ,这为我们获取数据,方便了不少 ,我们直接取出li中的属性就可以将电影信息获取到了 。

    第二步 : 下载网页内容

    我们需要将网页中的数据提取出去 , 就需要先将网页内容下载下来,写Java程序的朋友应该知道 , 如果使用Java内置网络请求,将网页数据下载下来,那将要写多少行代码,实话说,Java的网络请求真的很不友好,幸而Java社区异常强大,涌现了一批又一批比较好用的网络请求框架,如OkHttp,liteHttp等等,大大简化了我们的工作。但是,在Python中,将一个网页数据下载下来,只需要一行 。

    with request.urlopen('https://movie.douban.com/cinema/nowplaying/shenzhen/') as response:
    

    这是Python内置的urllib下的requests对象,将下载好的二进制数据封装在response对象里面,使用readlines方法就可以将其读取出来 。

    from urllib import request
    from urllib import parse
    
    # 打开链接,并得到返回值
    with request.urlopen('https://movie.douban.com/cinema/nowplaying/shenzhen/') as response:
          conent_list = response.readlines() # 得到一个byte类型的list
          #打印内容
          for content in conent_list:
              print(content .decode()) # 因为content是byte类型,所以需要解码成str类型
    
    

    虽然内置urlib可以完成我们的需求,但是我们不会用系统内置,因为还是比较麻烦,我们将使用富有盛名的requets库,虽然名字和系统内置的差不多,但是确实截然不同的库 。系统库是在urllib模块下,而requests就在requests模块下 。

    安装requests

    pip install requests
    

    example

    # url 请求地址
    # headers 请求头
    url = 'https://movie.douban.com/cinema/nowplaying/shenzhen/'
    res = requests.get(url,headers=headers)
    res.text() # 得到请求的文本内容
    

    好戏,马上开场

    第三步 : 解析网页内容

    解析是使用的Python内置的Html解析器,类似Java的jsoup.jar提供的api 。都是通过遍历Html dom树来进行分析,判断需要的tag ,然后进行属性解析。Python正在强大的Html解析器是,XPath解析,也是scrapy爬虫库内置的解析器 ,当然还是有beautifulsoup 。

    1.引入HTMLPaser

    from html.parser import HTMLParser
    

    2.新建解析类,继承HTMLPaser

    class MoviesParser(HTMLParser):
    

    3.overload handle_starttag方法 , 解析标签

    class MoviesParser(HTMLParser):
        def __init__(self):
            HTMLParser.__init__(self)
            # 电影列表list集合
            self.movies = []
            # 标签是否在li标签中的标识
            self.img_into_movie = False
            self.a_into_movie = False
    
        def handle_starttag(self, tag, attrs):
            # 因为属性都是key=val形式 , 所以根据属性名称取值
            def _attr(attrs,attr_name):
                for attr in attrs:
                    if attr[0] == attr_name:
                        return attr[1]
                return None
    
            # 取出属性值 , 根据每个Item的特征取值 ,因为有些Item的属性可能会重复 , 所以要尽量找出差异性,这样才能保证数据的准确性
            if tag == 'li' and _attr(attrs,'data-title') and _attr(attrs,'data-category') == 'nowplaying':
                movie = {}
                movie['title'] = _attr(attrs,'data-title')
                movie['score'] = _attr(attrs,'data-score')
                movie['star'] = _attr(attrs,'data-star')
                movie['duration'] = _attr(attrs,'data-duration')
                movie['region'] = _attr(attrs,'data-region')
                movie['director'] = _attr(attrs,'data-director')
                movie['actors'] = _attr(attrs,'data-actors')
                self.movies.append(movie)
                self.img_into_movie = True
                self.a_into_movie = True
    
            #获取海报图片
            if tag == 'img' and self.img_into_movie:
                self.img_into_movie = False
                img_src = _attr(attrs,'src')
                movie = self.movies[len(self.movies) -1]
                movie['poster_url'] = img_src
                # 下载图片
                donwload_poster_url(img_src)
            
            # 解析a标签,提取电影详情页的Url
            if tag == 'a' and self.a_into_movie:
                if _attr(attrs,'data-psource') == 'title':
                    self.a_into_movie = False
                    movie_url = _attr(attrs,'href')
                    movie = self.movies[len(self.movies) -1]
                    movie['movie_url'] = movie_url
    

    这是爬虫中最关键的部分,数据解析是保证数据正确的性的地方,解析没做好,就可能存在很多脏数据,这是我们应当避免的 。

    第四步 : 下载图片

    # 下载图片
    def donwload_poster_url(url):
        res = requests.get(url)
        file_name = str.split(url,'/')[-1]
        file_path = 'poster_img/' + file_name
        print('download img file_path = ',file_path)
        with open(file_path,'wb') as f:
            f.write(res.content)
    

    我们直接使用requests库,get图片地址,得到图片的二进制数据,再见二进制数据写入到文件中,这样我们的图片文件就下载好了。

    完整源码

    # 使用requests爬豆瓣正在上映的电影
    from html.parser import HTMLParser
    import requests
    
    
    class MoviesParser(HTMLParser):
        def __init__(self):
            HTMLParser.__init__(self)
            self.movies = []
            self.img_into_movie = False
            self.a_into_movie = False
    
        def handle_starttag(self, tag, attrs):
            # 根据属性名称取值
            def _attr(attrs,attr_name):
                for attr in attrs:
                    if attr[0] == attr_name:
                        return attr[1]
                return None
            # 取出属性值
            if tag == 'li' and _attr(attrs,'data-title') and _attr(attrs,'data-category') == 'nowplaying':
                movie = {}
                movie['title'] = _attr(attrs,'data-title')
                movie['score'] = _attr(attrs,'data-score')
                movie['star'] = _attr(attrs,'data-star')
                movie['duration'] = _attr(attrs,'data-duration')
                movie['region'] = _attr(attrs,'data-region')
                movie['director'] = _attr(attrs,'data-director')
                movie['actors'] = _attr(attrs,'data-actors')
                self.movies.append(movie)
                self.img_into_movie = True
                self.a_into_movie = True
    
            #获取海报图片
            if tag == 'img' and self.img_into_movie:
                self.img_into_movie = False
                img_src = _attr(attrs,'src')
                movie = self.movies[len(self.movies) -1]
                movie['poster_url'] = img_src
                donwload_poster_url(img_src)
    
            if tag == 'a' and self.a_into_movie:
                if _attr(attrs,'data-psource') == 'title':
                    self.a_into_movie = False
                    movie_url = _attr(attrs,'href')
                    movie = self.movies[len(self.movies) -1]
                    movie['movie_url'] = movie_url
    
    
    # 下载图片
    def donwload_poster_url(url):
        res = requests.get(url)
        file_name = str.split(url,'/')[-1]
        file_path = 'poster_img/' + file_name
        print('download img file_path = ',file_path)
        with open(file_path,'wb') as f:
            f.write(res.content)
    
    
    def douban_movies(url):
        #首先构建请求头 ,模拟浏览器请求头
        headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}
        # # 打开链接,并得到返回值
        res = requests.get(url,headers=headers)
        # 创建Html解析器
        moviesParser = MoviesParser()
        # 解析Html数据
        moviesParser.feed(res.text)
        return moviesParser.movies
    
    if __name__ == '__main__':
        url_str = 'https://movie.douban.com/cinema/nowplaying/shenzhen/'
        movies_res = douban_movies(url_str)
    
        import json
        json_str = json.dumps(movies_res,sort_keys=True,indent=4,separators=(',',': '))
        # 打印json数据
        print(json_str)
    

    从下载数据到解析Html,只用了七十多行 ,包含了注释和空格,真是人生苦短,我用Python

    0x004 结语

    Python确实是一个比较简洁的语言,学起来也相对比较轻松,各种库应有尽有,可以作为获取数据的不二选择 。其实,解析Html 还可以简化,使用Xpath更加简洁,几行代码就可以搞定,在后续的文章中,我会逐一介绍 。

    有时候感觉文字的表现力真是太弱了,特别是对于技术文章,因为涉及的多,很多时候写着写着就啰嗦了,然后删掉 。 俗话说:子不如表 , 表不如图,图不如视频 。最近关注了一个简书的作者,他做了一系列的视频,讲得挺好的,我思考着,要不要出个爬虫的视频教程 。

    相关文章

      网友评论

      • Eugene1024:我想知道最后的作者是谁:smile:
        逝我:@z不羁的风 变形金刚 !
        Eugene1024:@逝我 疗效咋的 虎虎生威么
        逝我:是谁不重要 , 关键看疗效 !

      本文标题:Python爬虫之爬豆瓣电影数据

      本文链接:https://www.haomeiwen.com/subject/ugattxtx.html