python爬虫——百度贴吧图片爬取 小项目

项目目的:

  1. 爬取贴吧中所有帖子里面的图片
  2. 将爬取到的图片存储到名称为贴吧名称的文件夹中

项目环境

  • python版本:python3.6
  • 用到的库:requests、etree、unquote
  • 浏览器:Chrome浏览器

一、页面分析

这里我以lol吧为例,进行分析。
右键点击‘检查’,鼠标移到某个帖子上,可以下图所示。
在这里插入图片描述
我们观察到在电脑网页中,百度贴吧html结构较为复杂,在这里我们可以用到一个小技巧。

分析网页结构小技巧

由于电脑版的网页html结构一般较为复杂,但是一般手机版的网页html结构会相对简单许多,所以我们可以在浏览器中,浏览手机版的网页来进行结构分析,这样可以有效地提高我们对网页结构的分析效率。

如何在浏览器中浏览手机版的网页?

我这里以谷歌浏览器为例进行演示。
在网页中点击‘右键——检查’

在这里插入图片描述
可以看到网页上方出现这行东西。点击最左边的‘Responsive’,会出现一些手机型号(如下图)。
在这里插入图片描述
下面点击iphone6,刷新后,依然‘右键——检查’与上面同样的帖子,这时候就会发现,网页的html结构比起全民的简单了许多。
在这里插入图片描述
但是别着急,还有跟简单的,下面点击‘Nokia Lumia 520’,(如果没有,可以点击列表最下方的Edit进行添加),这是一款非常老的诺基亚手机了,点击完,刷新后,就会能进入到最早的贴吧版本(满满的回忆有没有)。
大家也可以点击下面的地址去看一下:
https://tieba.baidu.com/mo/q—8D7E9D770BA62B40B3067027DC06EABD%3AFG%3D1–1-3-0----wapp_1554963358611_228/m?kw=lol&lp=5011&lm=&pn=0
还是右键点击刚刚那条帖子,这时会发现,这个版本的贴吧网页html结构是超级简单了。
在这里插入图片描述
然后点进去看一下,我们需要爬取的图片有没有
在这里插入图片描述
我们发现网页上的图片需要点击后才能进行查看,但是‘右键——检查’,我们需要的图片地址已经有了,红色框起来的便是。

既然有了简单的页面,我们当然就选择用简单的页面进行数据爬取工作啦。

二、开始编写爬虫程序

主要爬取逻辑

  1. 获取首页地址
  2. 发送请求,获取响应
    进入贴吧首页
  3. 提取数据,获取下一页的url地址
    3.1 提取列表页的url地址
    3.2 请求列表页的url地址,提取下一页的地址
    进入详情页
    3.3 提取详情页的图片,提取下一页的地址
    3.4 保存图片
    3.5 请求下一页的地址,循环执行3.2-3.5
  4. 请求(列表页)下一页的url地址,循环执行2-4

项目源代码

import json
import os
from urllib.parse import unquote

import requests
from lxml import etree


class TiebaSpider:

    def __init__(self, tieba_name):
        '''
        :param tieba_name: 贴吧名称
        '''
        self.tieba_name = tieba_name
        self.part_url = 'https://tieba.baidu.com/mo/q---8D7E9D770BA62B40B3067027DC06EABD%3AFG%3D1--1-1-0--2--wapp_1554901733618_210'  # 部分获取的地址缺少前面这部分
        self.start_url = 'https://tieba.baidu.com/mo/q---8D7E9D770BA62B40B3067027DC06EABD:FG=1--1-1-0--2--wapp_1554901733618_210/m?kw=' + tieba_name + '&pn=0'  # 首页地址
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Mobile Safari/537.36'}

        if not os.path.isdir(tieba_name):
            os.mkdir(tieba_name)

    def parse_url(self, url):
        '''
        发送请求,获取响应
        :param url: url地址
        :return: html页面内容
        '''
        response = requests.get(url, headers=self.headers)
        return response.content

    def sava_img(self, img):
        '''
        保存图片
        :param img:图片的下载链接
        '''
        file_path = self.tieba_name
        img_name = img.split('/')[-1]
        img = requests.get(img)
        print('图片名称',img_name)
        with open(os.path.join(file_path, img_name), 'wb') as f:
            f.write(img.content)

    def save_detail_img(self, detail_url):
        '''
        获取帖子图片并作保存处理
        (这里用到递归,需要理解透彻)
        :param detail_url: 详情页地址
        :return: 图片总列表
        '''
        # 3.2 请求列表页的url地址,提取下一页的地址
        detail_html_str = self.parse_url(detail_url)
        detail_html = etree.HTML(detail_html_str)
        # 3.3 提取详情页下一页的图片,提取下一页的地址
        img_list = detail_html.xpath("//a[text()='图']/@href")

        # 获取的网页上的图片地址:http://www.w3.org/1999/xhtml" href="http://c.hiphotos.baidu.com/forum/w%3D400%3Bq%3D80%3Bg%3D0/sign=5c474de444ed2e73fce9872cb73ad0b6/ec528e82b9014a909c3ee4dda7773912b31bee10.jpg?&src=http%3A%2F%2Fimgsrc.baidu.com%2Fforum%2Fpic%2Fitem%2Fec528e82b9014a909c3ee4dda7773912b31bee10.jpg
        # 由于网页上的获取的图片地址经过编码压缩,所以下面进行解码操作
        for img in img_list:
            img = unquote(str(img))
            # 保存该贴子的图片
            self.sava_img(img)
        print('保存成功')
        # 3.4 请求详情页下一页的地址,进入循环3.2-3.4
        detail_next_url = detail_html.xpath("//a[text()='下一页']/@href")
        if len(detail_next_url) > 0:
            detail_next_url = self.part_url + detail_next_url[0]
            return self.save_detail_img(detail_next_url)

    def run(self):
        '''实现主要逻辑'''
        next_url = self.start_url
        while next_url is not None:
            # 1.start_url
            # 2.发送请求,获取响应
            html_str = self.parse_url(next_url)
            html = etree.HTML(html_str)
            # 3.保存图片,提取下一页的url地址
            # 3.1 提取列表页的url地址
            # 3.2 请求列表页的url地址,提取下一页的地址
            # 3.3 保存图片
            # 3.4 提取详情页下一页的地址
            # 3.5 请求详情页下一页的地址,进入循环3.2-3.4
            div_list = html.xpath("//div[@class='i']")    # 将每个帖子的div分块
            for div in div_list:       # 遍历每块帖子的div
                href = self.part_url + div.xpath('./a/@href')[0] if len(div.xpath('./a/@href')) > 0 else None   # 获取帖子详情页地址
                self.save_detail_img(href)    # 进入详情页并保存图片

            # 3.5提取下一页url地址
            next_url = self.part_url + html.xpath("//a[text()='下一页']/@href")[0] if len(html.xpath("//a[text()='下一页']/@href")) > 0 else None
            # 4.请求(详情页)下一页的url地址,进入循环2-4



if __name__ == '__main__':
    tieba_spider = TiebaSpider('lol')
    tieba_spider.run()

运行结果

lol吧
在这里插入图片描述

李毅吧
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值