手把手教你爬取豆瓣Top250

最近在家看了些关于爬虫的资料,发一个小项目给想学爬虫的人带个路~尽可能地介绍一下每步的理由和做法。关于爬虫的资料太多了,初学者很容易迷失在各种各样的框架、库中(比如博主),也是借这个小项目给大家理一下爬虫的学习路程!
一般而言,其实爬虫就是三个步骤:(1)网页爬取(2)数据解析(3)数据存储
网页爬取: 获取你需要的网页的HTML代码(这部分需要注意一下反爬虫机制),常用的库有:urllib或者requests,二者选其一即可
数据解析: 从获取的HTML代码中得到自己想要的数据,常用的库:lxml(xpath语法)或者beautifulSoup4或者re(正则),三者最好都要学,初学者可以从beautifulSoup4开始学。在我看来,数据解析是整个爬虫的精华也是难点。
数据存储: 很容易理解,即把解析到的数据存储为自己想要的格式。

网页爬取

使用requests库
按下F12,进入开发者模式,选中Network,然后刷新,可以看到一个数据包,选中,查看其Headers。豆瓣的对爬虫很友好,我们的headers中只需要伪装两项:Referer和User-Agent,将浏览器中的复制下来即可!
在这里插入图片描述

import requests
#设置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)

有一点需要说明,为什么是发送get请求,也是在NetWork-Headers中得知的,一般而言,常用的是get和post请求。
在这里插入图片描述
我们可以得到html.txt如下:
在这里插入图片描述

数据解析

使用lxml库
首先先对HTML代码分析,同样是在开发者模式下,定位到整个需要爬取的页面,可以看到在class = grid_view的<ol>下面有一串的<li>标签,每个<li>标签即为一个电影。
在这里插入图片描述

from lxml import etree
import requests
#设置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
print(etree.tostring(movie, encoding='utf-8').decode('utf-8')) #打印li标签中的HTML代码

得到HTML代码如下:

        <li>
            <div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https://movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https://movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救赎</span>
                                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                                <span class="other">&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                        </a>


                            <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                        </p>

                        
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v:average">9.7</span>
                                <span property="v:best" content="10.0"></span>
                                <span>1857327人评价</span>
                        </div>

                            <p class="quote">
                                <span class="inq">希望让人自由。</span>
                            </p>
                    </div>
                </div>
            </div>
        </li>
        <li>

继续分析,这里取三种数据为例
title:可以看到<img>标签的alt属性即为电影名
img:可以看到<img>标签的src属性即为图片地址
rating:可以看到class属性为star的<div>标签下的class属性为rating_num的<span>中的文字内容即为评分

from lxml import etree
import requests
#设置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
title = movie.xpath(".//img/@alt")[0]
img = movie.xpath(".//img/@src")[0]
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0]
print("名称:", title, "\n图片: ", img, "\n评分:", rating)

运行结果
在这里插入图片描述

数据存储

电影的图片下载到文件夹,其他的数据存储到json文件中,这里还是用肖申克的救赎为例。

import json
from lxml import etree
import requests
#设置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值

response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
    f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
title = movie.xpath(".//img/@alt")[0] #名称
img = movie.xpath(".//img/@src")[0] #图片url
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #评分
movieUrl = movie.xpath(".//a/@href")[0] #电影链接
quote = movie.xpath(".//span[@class='inq']/text()")[0] #语录
info = {"名称": title, "评分": rating, "链接": movieUrl, "语录": quote} #信息存储为字典
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps(info, ensure_ascii=False, indent=4, separators=(',', ':')))
#保存图片
with requests.get(img, stream=True, headers=headers) as resp:
    with open('./img/1.jpg', 'wb') as fd:
        for chunk in resp.iter_content():
            fd.write(chunk)

完整代码

以上完成了肖申克的救赎的信息存储和图片存储,其他电影的同理,只需要增加一些循环即可。
另外我们爬取的https://movie.douban.com/top250只有25个电影,其他还有9个页面,点下一个页面的url为https://movie.douban.com/top250?start=25&filter=,可以发现规律,每次start递进25。
整理一下代码:

import requests
from lxml import etree
import json
#设置Headers值
headers = {
    'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
    'Referer': 'https://movie.douban.com/top250'
}
cnt = 1
infos = []
for i in range(0, 250, 25):
    url = 'https://movie.douban.com/top250?start='+str(i)+'&filter=' # url值
    response = requests.get(url, headers=headers) #使用requests库发送post请求
    text = response.text #获取html代码
    #存储得到的html代码
    # with open('./html.txt', 'w', encoding='utf-8') as f:
    #     f.write(text)
    html = etree.HTML(text)
    ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
    movies = ul.xpath("./li") #查找该ol标签下的li标签,这里取第一项
    # print(etree.tostring(movies, encoding='utf-8').decode('utf-8')) #打印li标签中的HTML代码
    for movie in movies:
        title = movie.xpath(".//img/@alt")[0] #名称
        img = movie.xpath(".//img/@src")[0] #图片url
        rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #评分
        movieUrl = movie.xpath(".//a/@href")[0] #电影链接
        quote = movie.xpath(".//span[@class='inq']/text()") #语录
        quote = " " if not quote  else quote[0]
        info = {"名称": title, "排名": cnt, "评分": rating, "链接": movieUrl, "语录": quote} #信息存储为字典
        infos.append(info)
        #保存图片
        with requests.get(img, stream=True, headers=headers) as resp:
            with open('./img/'+str(cnt)+'.jpg', 'wb') as fd:
                cnt += 1
                for chunk in resp.iter_content():
                    fd.write(chunk)
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps(infos, ensure_ascii=False, indent=4, separators=(',', ':')))

结果截图:
在这里插入图片描述
在这里插入图片描述

发布了466 篇原创文章 · 获赞 91 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章