Qt+Python开发百度图片下载器

一、资源下载地址

https://www.aliyundrive.com/s/jBU2wBS8poH

本项目路径:项目->收费->百度图片下载器(可试用5分钟)

安装包直接下载地址:http://139.9.165.1/media/BaiduPicDown.exe

二、项目介绍

1、本项目使用Vs2019+Qt+Python库来开发一个百度图片播放下载器(支持Gif)。

Qt播放Gif图片参考文章:

https://www.cnblogs.com/liangqin/p/15161809.html

本文主要描述Qt调用Python库来获取百度图片。

2、本项目完成的功能如下:

(1)、支持通过搜索关键词及图片张数来获取百度图片进行循环播放及保存原文件。

(2)、支持设置播放图片窗口大小。

(3)、支持Gif图片。

3、效果展示:

三、项目开始

1、准备工作

搭建一份Qt播放Gif图片的工程环境。然后获取python对应平台的头文件及库:

注意:安装的pythonLib目录下有很多文件,整个目录比较大,不便于我们程序发布。我们只需要保留程序所需要的文件即可,找到本程序的安装路径即可看到基本所需的Lib文件。

2、python程序来爬取百度图片

这里参考文章:

https://blog.csdn.net/xiligey1/article/details/73321152

然后进行简单修改,提供一个getImgUrls(key,num)接口给C++调用获取当前关键词多少张urls,提供一个getImg()接口给C++调用循环获取爬取到的图片,该接口返回给C++的是图片的base64编码。

修改后的内容如下:

baidu_photo_spider.py

  1 """根据搜索词下载百度图片"""
  2 import os
  3 import re
  4 import base64
  5 import time
  6 from typing import List, Tuple
  7 from urllib.parse import quote
  8 
  9 import requests
 10 
 11 from conf import *
 12 
 13 # 关键词, 改为你想输入的词即可, 相当于在百度图片里搜索一样
 14 keyword = '治愈系柴犬'
 15 
 16 # 最大下载数量
 17 max_download_images = 100
 18 
 19 all_pic_urls = []
 20 count = 0
 21 
 22 def get_page_urls(page_url: str, headers: dict) -> Tuple[List[str], str]:
 23     """获取当前翻页的所有图片的链接
 24     Args:
 25         page_url: 当前翻页的链接
 26         headers: 请求表头
 27     Returns:
 28         当前翻页下的所有图片的链接, 当前翻页的下一翻页的链接
 29     """
 30     if not page_url:
 31         return [], ''
 32     try:
 33         html = requests.get(page_url, headers=headers)
 34         html.encoding = 'utf-8'
 35         html = html.text
 36     except IOError as e:
 37         print(e)
 38         return [], ''
 39     pic_urls = re.findall('"objURL":"(.*?)",', html, re.S)
 40     next_page_url = re.findall(re.compile(r'<a href="(.*)" class="n">下一页</a>'), html, flags=0)
 41     next_page_url = 'http://image.baidu.com' + next_page_url[0] if next_page_url else ''
 42     return pic_urls, next_page_url
 43 
 44 def getImgUrls(key,num):
 45     global keyword
 46     global max_download_images
 47     global all_pic_urls
 48     keyword = key
 49     max_download_images = num
 50     url_init = url_init_first + quote(keyword, safe='/')
 51     page_urls, next_page_url = get_page_urls(url_init, headers)
 52     all_pic_urls.extend(page_urls)
 53     page_count = 0
 54     while 1:
 55         page_urls, next_page_url = get_page_urls(next_page_url, headers)
 56         page_count += 1
 57         print('正在获取第%s个翻页的所有图片链接' % str(page_count))
 58         if next_page_url == '' and page_urls == []:
 59             print('已到最后一页,共计%s个翻页' % page_count)
 60             return
 61         all_pic_urls.extend(page_urls)
 62         if len(all_pic_urls) >= max_download_images:
 63             print('已达到设置的最大下载数量%s' % max_download_images)
 64             return
 65 
 66 def down_pic(i,pic_url):
 67     try:
 68         pic = requests.get(pic_url, timeout=15)
 69         image_output_path = './images/' + str(i + 1) + '.jpg'
 70         with open(image_output_path, 'wb') as f:
 71             f.write(pic.content)
 72             print('成功下载第%s张图片: %s' % (str(i + 1), str(pic_url)))
 73     except IOError as e:
 74         print('下载第%s张图片时失败: %s' % (str(i + 1), str(pic_url)))
 75         print(e)
 76         return
 77 
 78 def getImg():
 79     global all_pic_urls
 80     global count
 81     global max_download_images
 82     none='none'
 83     try:
 84         pic = requests.get(list(set(all_pic_urls))[count], timeout=15)
 85         imgbase64 = base64.b64encode(pic.content).decode()
 86         #print(count)
 87         count += 1
 88         if count == max_download_images:
 89             count = 0
 90         return imgbase64,none
 91     except IOError as e:
 92         print(e)
 93         return none,none
 94 
 95 if __name__ == '__main__':
 96     if not os.path.exists('./images'):
 97         os.mkdir('./images')
 98 
 99     getImgUrls('', 2)
100     
101     #下载图片
102     for i, pic_url in enumerate(list(set(all_pic_urls))[:max_download_images]):
103         down_pic(i, pic_url)
104 
105     #循环读取列表中的图片
106     while 1:
107         print(getImg())
108         time.sleep(5)

 3、封装C++调用python库的接口

直接上代码:

 1 #include "PythonDevApi.h"
 2 #include "Python.h"
 3 
 4 void initPython()
 5 {
 6     Py_Initialize();//加载Python解释器
 7     PyRun_SimpleString("import sys");
 8     PyRun_SimpleString("sys.path.append('Dlls/')");
 9 }
10 
11 void unInitPython()
12 {
13     Py_Finalize();//卸载Python解释器
14 }
15 
16 static PyObject* pBaiduModule = NULL;
17 
18 int pyGetBaiduImgInit(const char* key, int num)
19 {
20     pBaiduModule = PyImport_ImportModule("baidu_photo_spider");//Python py文件名
21     PyImport_ReloadModule(pBaiduModule);
22     if (pBaiduModule == nullptr)
23         return -1;
24 
25     PyObject* pFunc = NULL;
26     PyObject* pArgs = NULL;
27     PyObject* pResult = NULL;
28     pFunc = PyObject_GetAttrString(pBaiduModule, "getImgUrls");//py文件内函数名
29     //执行函数
30     pArgs = Py_BuildValue("si", key, num);
31     pResult = PyObject_CallObject(pFunc, pArgs);
32     
33     return 0;
34 }
35 
36 int pyGetBaiduImgWork(char* img, int imgSize)
37 {
38     //执行函数
39     PyObject* pBaiduFunc = PyObject_GetAttrString(pBaiduModule, "getImg");//py文件内函数名
40     if (pBaiduFunc == NULL)
41         return -1;
42 
43     PyObject* pArgs = NULL;
44     PyObject* pResult = PyObject_CallObject(pBaiduFunc, pArgs);
45     if (pResult == NULL)
46         return -1;
47 
48     char* imgbase64, * none;
49     int ret = PyArg_ParseTuple(pResult, "s|s", &imgbase64, &none);
50     if (ret == 1)
51     {
52         if (memcmp(imgbase64, none, strlen(none)) != 0 && img != NULL && strlen(imgbase64) < imgSize)
53         {
54             memcpy(img, imgbase64, strlen(imgbase64));
55             return 0;
56         }
57     }
58     else
59     {
60         printf("ret:%d\n", ret);
61     }
62     
63     return -1;
64 }
65 
66 int pyGetBaiduImgUninit()
67 {
68     return 0;
69 }

4、调用封装好的python接口来进行图片获取与保存文件:

 1 void GuiQtDevThread::run()
 2 {
 3     int count = 0;
 4 
 5     pyGetBaiduImgInit(m_key.toStdString().c_str(), m_num);
 6 
 7     while (1)
 8     {
 9         //程序退出时终止线程
10         if (m_gui->getGetImgThreadState() == THREAD_STATE_E_PrepareStop)
11         {
12             m_gui->setGetImgThreadState(THREAD_STATE_E_Stop);
13             pyGetBaiduImgUninit();
14             return ;
15         }
16         count++;
17         if (count == 50)
18         {
19             count = 0;
20             //只能使用emit方式操作控件,直接操作控件会死机,这里会等待槽函数结束才继续运行(Qt::BlockingQueuedConnection)
21             memset(m_img, 0, m_img_size);
22             int ret = pyGetBaiduImgWork(m_img, m_img_size);
23             if (ret != 0)
24             {
25                 QThread::msleep(100);
26                 continue;
27             }
28 
29             QByteArray decodeimg = QByteArray::fromBase64(m_img);
30 
31             CQVString filenamet;
32             filenamet.Append("%s%d", "imgtmp", _getpid());
33             QFile file(filenamet.GetBuffer());
34             file.open(QIODevice::WriteOnly);
35             file.write(decodeimg);
36             file.close();
37             QThread::msleep(50);
38 
39             QString saveFileName = m_gui->getSaveDir();
40             if (saveFileName.length() > 1)
41             {
42                 bool dirExist = true;
43                 QDir dir;
44                 if (!dir.exists(saveFileName))
45                 {
46                     dirExist = dir.mkdir(saveFileName);
47                 }
48 
49                 if (dirExist)
50                 {
51                     CQVString filenamet;
52                     filenamet.Append("%s%d", "imgtmp", _getpid());
53                     QImageReader reader(filenamet.GetBuffer());
54                     reader.setDecideFormatFromContent(true);
55                     int nCount = reader.imageCount();
56                     if (nCount > 0 && reader.canRead())
57                     {
58                         QString fileFomate(QImageReader::imageFormat(filenamet.GetBuffer()));
59 
60                         saveFileName += "/";
61                         QDateTime current_date_time = QDateTime::currentDateTime();
62                         QString current_date = current_date_time.toString("yyyy-MM-dd-hh-mm-ss");
63                         saveFileName += current_date;
64                         saveFileName += ".";
65                         saveFileName += fileFomate;
66                         QFile saveFile(saveFileName);
67                         saveFile.open(QIODevice::WriteOnly);
68                         saveFile.write(decodeimg);
69                         saveFile.close();
70                         QThread::msleep(50);
71 
72                     }
73                 }
74             }
75 
76             m_gui->setFileChange();
77         }
78         QThread::msleep(100);
79     }
80 }

 5、项目生成后事件需要把pythondll拷贝到exe目录下,并且把pythonDLLsLib目录以及我们写的py程序拷贝到主工程和exe目录下。这样才能保证vs2019和双击exe正常运行程序,如图:

 

 

posted @ 2021-09-15 14:04  亮琴软件工作室  阅读(166)  评论(0编辑  收藏  举报