一、背景知识

最近看微信公众号,发现很多有趣的图片,又不想一一保存,遂产生通过 python 爬虫的方式直接一次性解析保存。

在此过程中,使用到rerequestsosbs4.BeautifulSouptimePIL 等多个库,算是综合使用了一下。

有所收获。

二、整体思路

  • 分析网页源代码
  • 获取图片的 URL
  • 根据 URL 保存下载
  • 根据图片分辨率进行二次过滤

三、具体分析

1.标题

标题存放在 <h1 class> 标签之下,使用 bs.select 即可获取。

2.图片

图片存放在 img 标签之下,对应的 URL 存放在 data-src 字段。

图片路径通过 os.path.exists() 判断是否存在。

图片内容通过 requests.get(url).content 进行下载保存。

四、实操

1.准备工作

import re
import requests
import os
from bs4 import BeautifulSoup
import urllib
import time
from PIL import Image

# 头部文件
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36', 'Connection': 'close'
}

2.请求网站

# 待爬取网站
url = r'https://mp.weixin.qq.com/s/zyxFlgm_th1KGWwsEylCVQ' # 我今天非得跟你玩
url = r'https://mp.weixin.qq.com/s/xgwt2ujb1AD_d3_iWhLP2Q' # 这些年,我们看过的那些媛们!

# 请求
response = requests.get(url, headers=headers)
print(response.status_code) # 200 代表正常返回
response.raise_for_status() # 如果异常抛出错误

3.bs4解析标题

# bs4解析
bs = BeautifulSoup(response.text, 'html.parser')
title = bs.select('h1')[0].text.strip()
# title = bs.find_all('h1')[0].text.strip()

# 过滤标题中的中文
title = re.findall('[\u4e00-\u9fa5a-zA-Z0-9]+', title, re.S)
title = '-'.join(title)

4.图片解析

# 第1种解析方式
imglist = []
for img in bs.select('img'):
    if 'data-src' in img.attrs:
        imglist.append(img['data-src'])

# 第2种解析方式
imglist2 = []
imgs = bs.find_all('img', attrs={'data-type':'gif'})
if imgs is not None:
    for img in imgs:
        print(img['data-src'])
        imglist2.append(img['data-src'])

5.路径生成

# 判断路径是否存在
path = r'C:\Users\Hider\Desktop\图片'
if not os.path.exists(path):
    os.mkdir(path)

if not os.path.exists(os.path.join(path, title)):
    os.mkdir(os.path.join(path, title))

6.图片下载

# 第1种方式下载图片
num = 0
for jpg_url in imglist:
    result = requests.get(jpg_url, headers=headers).content
    f = open(os.path.join(path, title, str(num+1) + '.gif'), 'wb')
    f.write(result)
    f.close()
    num += 1
    print(f'正在下载第{num}张...')
    time.sleep(1)

# 第2种方式下载图片
path = r'C:\Users\Hider\Desktop\图片'
for jpg_url in imglist:
    try:
        picture_name = jpg_url.split('/')[-2]
        fmt = jpg_url.split('=')[-1]
        result = requests.get(jpg_url, headers=headers).content
        with open(path + '\\' + title + '\\' + picture_name + '.' + fmt, 'wb+') as f:
            f.write(result)
    except Exception as reason:
        print(str(reason))
        
# 第3种方式下载图片 -- 好像快很多!!!
path = r'C:\Users\Hider\Desktop\图片'
for jpg_url in imglist:
    try:
        picture_name = jpg_url.split('/')[-2]
        fmt = jpg_url.split('=')[-1]
        # urllib.request.urlretrieve(jpg_url, '{0}{1}.gif'.format(path, picture_name))
        urllib.request.urlretrieve(jpg_url, path + '\\' + title + '\\' + picture_name + '.' + fmt)
    except Exception as reason:
        print(str(reason))

7.图片过滤

# 过滤图片
file_list = os.listdir(os.path.join(path, title))
for file in file_list:
    if file.split('.')[-1] == 'gif':
        filename = os.path.join(path, title, file)
        img = Image.open(filename)
        imgSize = img.size
        img.close()
        # print(imgSize)
        if imgSize[0] > 700 and imgSize[1] > 700:
            pass
            # print(imgSize)
        else:
            os.remove(filename) # 删除文件
            print(file)

五、封装函数

import re
import requests
import os
from bs4 import BeautifulSoup
import urllib
import time
from PIL import Image

def wechat_picture_download(url, path):
    # 头部文件
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36', 'Connection': 'close'
    }    
    # 请求
    response = requests.get(url, headers=headers)
    print(response.status_code) # 200 代表正常返回
    response.raise_for_status() # 如果异常抛出错误
    # bs4解析
    bs = BeautifulSoup(response.text, 'html.parser')
    title = bs.select('h1')[0].text.strip()
    # title = bs.find_all('h1')[0].text.strip()    
    # 过滤标题中的中文
    title = re.findall('[\u4e00-\u9fa5a-zA-Z0-9]+', title, re.S)
    title = '-'.join(title)
    # 解析
    imglist = []
    for img in bs.select('img'):
        if 'data-src' in img.attrs:
            imglist.append(img['data-src'])
    # 判断路径是否存在
    if not os.path.exists(path):
        os.mkdir(path)
    if not os.path.exists(os.path.join(path, title)):
        os.mkdir(os.path.join(path, title))
    num = 0
    for jpg_url in imglist:
        try:
            # urllib.request.urlretrieve(jpg_url, '{0}{1}.gif'.format(path, picture_name))
            print('正在下载:', str(num+1) + '.gif')
            urllib.request.urlretrieve(jpg_url, os.path.join(path, title, str(num+1) + '.gif'))
            time.sleep(1)
            num += 1
        except Exception as reason:
            print(str(reason))
    print('-'*10,'全部下载完成!!','-'*10)
    # 过滤图片
    file_list = os.listdir(os.path.join(path, title))
    for file in file_list:
        if file.split('.')[-1] == 'gif':
            filename = os.path.join(path, title, file)
            img = Image.open(filename)
            imgSize = img.size
            img.close()
            # print(imgSize)
            if imgSize[0] > 100 and imgSize[1] > 100:
                pass
                # print(imgSize)
            else:
                os.remove(filename) # 删除文件
                print('正在删除:', file)
    print('-'*10,'过滤完成!!','-'*10)
    return True
            
          
# 待爬取网站
# url = r'https://mp.weixin.qq.com/s/zyxFlgm_th1KGWwsEylCVQ' # 我今天非得跟你玩
url = r'https://mp.weixin.qq.com/s/xgwt2ujb1AD_d3_iWhLP2Q' # 这些年,我们看过的那些媛们!
path = r'C:\Users\Hider\Desktop\图片'

wechat_picture_download(url, path)  

参考链接:Python 判断文件夹是否存在(OS)

参考链接:抓取微信公众号文章中的图片

参考链接:python爬虫之爬取微信公众号文章中的图片