基于Python和C++实现的图像网络爬虫与图像处理

基于Python和C++实现的图像网络爬虫与图像处理 1,实验概述 设计,实现图片网络爬虫,从网站上批量下载图片;并对图片进行图像处理, 2,实验环境 语言 网络爬虫:Python 图片处理:C++ 软件环境 Visual Studio2015 Pycharm2017 3

本文包含相关资料包-----> 点击直达获取<-------

基于Python和C++实现的图像网络爬虫与图像处理

1、实验概述

设计、实现图片网络爬虫,从网站上批量下载图片;并对图片进行图像处理。

2、实验环境

  • 语言
  • 网络爬虫:Python
  • 图片处理:C++

  • 软件环境

  • Visual Studio2015
  • Pycharm2017

3、实验设计思路

4、实验实现

4.1 全局变量及导入的库

```python

coding=utf-8

urllib模块提供了读取Web页面数据的接口

import urllib.request

re模块主要包含了正则表达式

import re import requests import urllib.error import BitVector.BitVector import socket

如果连接时间超出2秒就跳过这个网址

socket.setdefaulttimeout(2.0)

urls = ["http://www.ivsky.com/"] # 自定义要爬去的链接 depth = 5 # 自定义爬去的深度 picNum = 0 ```

4.2 网址获取

python class MyCrawler: def __init__(self, seeds): # 初始化当前抓取的深度 self.currentDepth = 1 # 使用种子初始化url栈 self.linkQuence = linkQuence() self.bloomfilter = BloomFilter() if isinstance(seeds, str): self.linkQuence.addUnvisitedUrl(seeds) if isinstance(seeds, list): for i in seeds: self.linkQuence.addUnvisitedUrl(i)

定义了一个MyCrawler类用于获得当前页面的链接网址,其中成员linkQuence用于存储已访问过的网址和即将访问的网址;成员bloomfilter类用于网页去重。

```python

抓取过程主函数

def crawling(self, seeds, crawlDepth, static_url): # 循环条件:抓取深度不超过crawl_deepth while self.currentDepth <= crawlDepth: # 循环条件:待抓取的链接不空 print("depth",self.currentDepth) while len(self.linkQuence.visted) <= 1023 and not self.linkQuence.unVisitedUrlsEnmpy(): try: # url出栈 visitUrl = self.linkQuence.unVisitedUrlDeQuence() if visitUrl is None or visitUrl == "": continue elif (self.bloomfilter.isContaions(visitUrl) == True): continue self.bloomfilter.insert(visitUrl) # 获取超链接 links = self.getHyperLinks(visitUrl, static_url) # 将url放入已访问的url中 self.linkQuence.addVisitedUrl(visitUrl) #print(len(self.linkQuence.visted)) # 未访问的url入列 for link in links: if ("http" == str(i)[:4]): self.linkQuence.addUnvisitedUrl(link) except: continue self.currentDepth += 1 print("urlTotal:",len(self.linkQuence.visted)) ```

crawling函数用于抓取网页中的链接并将已访问过的网址加入已访问网址栈,当抓取深度超过自定义的需要爬取的深度即停止爬虫;当已访问过的不重复的网址超过1023或者未访问过的网址栈为空,即开始下一深度的爬取。将网址加入已访问网址栈时需要对其利用BloomFilter进行去重。爬取网址结束后打印出已访问网址栈的长度,即已访问的网址个数。

python # 获取源码中得超链接 def getHyperLinks(self, url, static_url): result = [] r = requests.get(url,allow_redirects=False) data = r.text #print(url) # 利用正则查找所有连接 link_list = re.findall(r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')", data) for i in link_list: if ("http" == str(i)[:4]): result.append(i) return result

通过requests中的get函数得到网页url中的源码内容存储在data中;正则表达式r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')"通过匹配从data中取出标签href中的内容;if判断筛选出有效超连接。

```python class linkQuence: def init (self): # 已访问的url集合 self.visted = [] # 待访问的url集合 self.unVisited = []

# 获取访问过的url栈
def getVisitedUrl(self):
    return self.visted

# 获取未访问的url栈
def getUnvisitedUrl(self):
    return self.unVisited

# 添加到访问过得url栈中
def addVisitedUrl(self, url):
    self.visted.append(url)

# 移除访问过得url
def removeVisitedUrl(self, url):
    self.visted.remove(url)


# 未访问过得url出栈
def unVisitedUrlDeQuence(self):
    try:
        return self.unVisited.pop()
    except:
        return None

# 保证每个url只被访问一次
def addUnvisitedUrl(self, url):
    if url != "" and url not in self.visted and url not in self.unVisited:
        self.unVisited.insert(0, url)

# 获得已访问的url数目
def getVisitedUrlCount(self):
    return len(self.visted)

# 获得未访问的url数目
def getUnvistedUrlCount(self):
    return len(self.unVisited)

# 判断未访问的url栈是否为空
def unVisitedUrlsEnmpy(self):
    return len(self.unVisited) == 0

```

实现一个网址访问栈类。

4.3 网页去重

```python class BloomFilter(): #n = 1200, m = 15000, k = 7 def init (self, BIT_SIZE=15000): self.BIT_SIZE = 15000 self.seeds = [5, 7, 11, 13, 31, 37, 61] # 建立一个大小为15000位的二进制向量,分配内存 self.bitset = BitVector.BitVector(size=self.BIT_SIZE) self.hashFunc = [] # 利用7个素数初始化7个随机数生成器 for i in range(len(self.seeds)): self.hashFunc.append(SimpleHash(self.BIT_SIZE, self.seeds[i]))

def insert(self, value):
    for f in self.hashFunc:
        loc = f.hash(value)
        self.bitset[loc] = 1

def isContaions(self, value):
    if value == None:
        return False
    ret = True
    for f in self.hashFunc:
        loc = f.hash(value)
        # 用同样的随机数产生方法对比相应位的二进制值,只要发现有一个不同即返回结果为假
        ret = ret & self.bitset[loc]
        if ret == False:
            return ret
            # 只有当7个二进制位都相等时才返回真
    return ret

```

实现一个BloomFilter类。根据公式

以及要求假阳性概率在0.1%之内,且应有至少1000个不重复的网址,则取布隆过滤器的n = 1200, m = 15000, k = 7。

```python class SimpleHash(): def init (self, capability, seed): self.capability = capability self.seed = seed

# 传入的value即为url值,ord(value[i])表示第i位字符的ascii码值
def hash(self, value):
    ret = 0
    for i in range(len(value)):
        ret += self.seed * ret + ord(value[i])
        # 最终产生的数是二进制向量最大下标与随机数的按位与结果
    return (self.capability - 1) & ret

```

利用DEK哈希算法生成哈希值。

4.4 图片下载

```python def getHtml(url): global picNum try: headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} url = urllib.request.Request(url=url, headers=headers) page = urllib.request.urlopen(url, timeout = 2) #urllib.urlopen()方法用于打开一个URL地址 html = page.read() #read()方法用于读取URL上的数据

    reg = r'src="([a-zA-Z0-9\.:/]+?\.jpg)"'  # 正则表达式,得到图片地址
    imgre = re.compile(reg)  # re.compile() 可以把正则表达式编译成一个正则表达式对象.
    html = html.decode("utf-8", "ignore")
    imglist = re.findall(imgre, html)  # re.findall() 方法读取html 中包含 imgre(正则表达式)的    数据
    # 把筛选的图片地址通过for循环遍历并保存到本地
    # 核心是urllib.urlretrieve()方法,直接将远程数据下载到本地,图片通过x依次递增命名
    for imgurl in imglist:
        try:
            if ("http" == str(imgurl)[:4]):
                urllib.request.urlretrieve(imgurl, 'E:\images\%s.jpg' % picNum)
                picNum += 1
        except:
            continue
except:
    print("something is wrong")

```

利用request库中的urlopen方法打开一个url地址并用read方法读取url上的数据;正则表达式r'src="([a-zA-Z0-9.:/]+?.jpg)"'用来获取url上的图片地址;再利用urlretrieve方法保存图片到本地。

4.5 图像处理

```python class PixImage { private: cv::Mat image; //图片名称 std::string name; //图片尺寸、高、宽 int size; int height; int width; //像素信息 uchar color; uchar colorR; uchar colorG; uchar colorB; //经过处理后的图片 cv::Mat imageCR; cv::Mat imageBluring; cv::Mat imageSobel; //读取图片像素信息 void colorRead(cv::Mat &image); //像素减少处理 void colorReduce(cv::Mat &image, cv::Mat &imageColorReduce); //模糊处理 void Bluring(cv::Mat &image, cv::Mat &imageBluring, int winSize); //将多通道图片转换成单通道 int GrayImage(cv::Mat &image, cv::Mat &imageSobel); //利用索贝尔算子检测图片边缘 void Sobel(int thresh, cv::Mat &imageSobel, cv::Mat &gray);

public: //根据图片名称构造函数 PixImage(string imageName) { image = cv::imread(imageName); if (image.empty()) { cout << "图像加载失败" << endl; exit(0); } name = imageName; size = image.cols image.rows; width = image.cols; height = image.rows; color = new uchar [height]; colorR = new uchar [height]; colorG = new uchar [height]; colorB = new uchar*[height]; colorRead(image); } //析构函数 ~PixImage() { delete []color; delete []colorR; delete []colorG; delete []colorB; }

void colorReduce() {
    colorReduce(image, imageCR);
}

void Bluring(int winSize) {
    Bluring(image, imageBluring, winSize);
}

void Sobel() {
    Mat gray;
    int thresh = GrayImage(image, gray);
    Sobel(thresh, imageSobel, gray);
}
//在屏幕上显示图片
void PicShow();
//保存图片
void PicSave(string name);

}; ```

定义了一个PixImage类,private部分存有图片的尺寸、像素信息、处理后的图片信息以及图片处理方式对应的函数;public部分有相应的像素处理函数接口、中值滤波图片模糊处理接口、sobel算子处理接口以及图片显示、保存的函数。

c++ //通过.ptr<>函数得到一行的指针,并用[]操作符访问某一列的像素值。 void PixImage::colorRead(cv::Mat &image) { Mat imageClone = image.clone(); int rowNumber = imageClone.rows; int colNumber = imageClone.cols; int div = 64; for (int i = 0; i < rowNumber; i++) { color[i] = imageClone.ptr<uchar>(i); colorR[i] = new uchar[colNumber]; colorG[i] = new uchar[colNumber]; colorB[i] = new uchar[colNumber]; for (int j = 0; j < colNumber; j++) { colorR[i][j] = color[i][3 * j]; colorG[i][j] = color[i][3 * j + 1]; colorB[i][j] = color[i][3 * j + 2]; } } }

利用.ptr<>函数访问并得到图片的像素信息。

c++ void PixImage::colorReduce(cv::Mat &image, cv::Mat &imageColorReduce) { imageColorReduce = image.clone(); int rowNumber = imageColorReduce.rows; int colNumber = imageColorReduce.cols*imageColorReduce.channels(); int div = 64; for (int i = 0; i < rowNumber; i++) { uchar* data = imageColorReduce.ptr<uchar>(i); for (int j = 0; j < colNumber; j++) { data[j] = data[j] / div*div + div / 2; } } }

对图像中的像素进行量化处理。如常见的RGB24图像有256*256*256中颜色,通过Reduce Color将每个通道的像素减少8倍至256/8=32种,则图像只有32*32*32种颜色。假设量化减少的倍数是N,则代码实现时就是简单的value/N*N,通常会再加上N/2以得到相邻的N的倍数的中间值,最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。

```c++ //均值滤波器消除噪声 void PixImage::Bluring(cv::Mat &image, cv::Mat &imageBluring, int winSize) { imageBluring = image.clone(); int rowNumber = imageBluring.rows; int colNumber = imageBluring.cols; uchar * data = new uchar [rowNumber]; int pos = (winSize - 1) / 2, temp = 0;

//模糊处理中间一圈
for (int i = pos; i < rowNumber - pos; i++) {
    data[i] = imageBluring.ptr<uchar>(i);
    for (int j = pos; j < colNumber - pos; j++) {
        temp = 0;
        //处理红色像素
        for (int winRow = 0; winRow < winSize; winRow++)
            for (int winCol = 0; winCol < winSize; winCol++)
                temp += colorR[i - pos + winRow][j - pos + winCol];
        data[i][j * 3] = temp / (winSize*winSize);
        temp = 0;
        //处理绿色像素
        for (int winRow = 0; winRow < winSize; winRow++)
            for (int winCol = 0; winCol < winSize; winCol++)
                temp += colorG[i - pos + winRow][j - pos + winCol];
        data[i][j * 3 + 1] = temp / (winSize*winSize);
        temp = 0;
        //处理蓝色像素
        for (int winRow = 0; winRow < winSize; winRow++)
            for (int winCol = 0; winCol < winSize; winCol++)
                temp += colorB[i - pos + winRow][j - pos + winCol];
        data[i][j * 3 + 2] = temp / (winSize*winSize);
    }
}
data[0] = imageBluring.ptr<uchar>(0);
data[rowNumber - 1] = imageBluring.ptr<uchar>(rowNumber - 1);

//处理左上角像素
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorR[i][j];
data[0][0] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorG[i][j];
data[0][1] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorB[i][j];
data[0][2] = temp / ((pos + 1)*(pos + 1));

//处理右上角像素
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = colNumber-pos-1; j < colNumber; j++)
        temp += colorR[i][j];
data[0][3 * (colNumber - 1)] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = colNumber - pos - 1; j < colNumber; j++)
        temp += colorG[i][j];
data[0][3 * (colNumber - 1) + 1] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = 0; i <= pos; i++)
    for (int j = colNumber - pos - 1; j < colNumber; j++)
        temp += colorB[i][j];
data[0][3 * (colNumber - 1) + 2] = temp / ((pos + 1)*(pos + 1));

//处理左下角像素
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorR[i][j];
data[rowNumber - 1][0] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorG[i][j];
data[rowNumber - 1][1] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = 0; j <= pos; j++)
        temp += colorB[i][j];
data[rowNumber - 1][2] = temp / ((pos + 1)*(pos + 1));

//处理右下角像素
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = colNumber - pos - 1; j < colNumber; j++)
        temp += colorR[i][j];
data[rowNumber - 1][3 * (colNumber - 1)] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = colNumber - pos - 1; j < colNumber; j++)
        temp += colorG[i][j];
data[rowNumber - 1][3 * (colNumber - 1) + 1] = temp / ((pos + 1)*(pos + 1));
temp = 0;
for (int i = rowNumber - pos - 1; i < rowNumber; i++)
    for (int j = colNumber - pos - 1; j < colNumber; j++)
        temp += colorB[i][j];
data[rowNumber - 1][3 * (colNumber - 1) + 2] = temp / ((pos + 1)*(pos + 1));
delete[]data;

} ```

利用均值滤波器消除噪声使图片模糊,即将任意一个像素,取其周围n*n个像素范围内的平均值来置换该像素;为了便于操作,将图片中间的像素与边缘像素分开处理。

c++ //三通道彩色图片转换成单通道图片 int PixImage::GrayImage(cv::Mat &image, cv::Mat &imageSobel) { int threshL = 0, thresh = 0; imageSobel = image.clone(); int rowNumber = imageSobel.rows; int colNumber = imageSobel.cols; for (int i = 0; i < rowNumber; i++) { uchar* data = imageSobel.ptr<uchar>(i); for (int j = 0; j < colNumber; j++) { data[j * 3] = (uchar)(0.136*data[j * 3] + 0.514*data[j * 3 + 1] + 0.350*data[j * 3 + 2]); data[j * 3 + 1] = data[j * 3]; data[j * 3 + 2] = data[j * 3]; threshL += data[3 * j]; } thresh += (threshL / colNumber); threshL = 0; } thresh = thresh/rowNumber; thresh = sqrt(200 * thresh); return thresh; }

灰度处理,即将多通道图片转换成单通道图片。将RGB像素值按照比例相加,并且使RGB三个通道的值相等即完成转换;并且求得该幅图片所有点灰度的平均值,即Sobel阈值。经多次试验比较,得出scale在200左右比较合适。

```c++ //利用索贝尔算子检测图片边缘 void PixImage::Sobel(int thresh, cv::Mat &imageSobel, cv::Mat &gray) { imageSobel = image.clone(); int rowNumber = imageSobel.rows; int colNumber = imageSobel.cols; uchar data = new uchar*[rowNumber]; uchar temp = new uchar*[rowNumber];

for (int i = 0; i < rowNumber; i++) {
    data[i] = image.ptr<uchar>(i);
    temp[i] = imageSobel.ptr<uchar>(i);
}

for (int i = 1; i < rowNumber - 1; i++) {
    for (int j = 1; j < colNumber - 1; j++) {
        int Gx = (data[i + 1][3 * (j - 1)] + 2 * data[i + 1][j * 3] + data[i + 1][3 * (j + 1)])
            - (data[i - 1][3 * (j - 1)] + 2 * data[i - 1][j * 3] + data[i - 1][3 * (j + 1)]);
        int Gy = (data[i - 1][3 * (j - 1)] + 2 * data[i][3 * (j - 1)] + data[i + 1][3 * (j - 1)])
            - (data[i - 1][3 * (j + 1)] + 2 * data[i][3 * (j + 1)] + data[i + 1][3 * (j + 1)]);
        uchar G = sqrt(Gx*Gx + Gy*Gy);
        if (G > thresh)
            temp[i][j*3] = (uchar)255;
        else
            temp[i][j*3] = (uchar)0;
        temp[i][j * 3 + 1] = temp[i][j * 3];
        temp[i][j * 3 + 2] = temp[i][j * 3];
    }
}
delete[]data;
delete[]temp;

} ```

利用索贝尔算子检测图片边缘。将图像与两组矩阵分别作平面卷积,得出横向及纵向的亮度差分近似值。若某点灰度值大于Sobel阈值,则将其赋值为255;若该点灰度值小于等于Sobel阈值,则将其赋值为0。

```c++ //显示图片 void PixImage::PicShow() { int timeShow = 1000; if (imageCR.empty()) { cout << "没有进行像素减少处理" << endl; } else { namedWindow("PicShow"); imshow("PicShow", imageCR); waitKey(timeShow); } if (imageBluring.empty()) { cout << "没有进行模糊处理" << endl; } else { namedWindow("PicShow"); imshow("PicShow", imageBluring); waitKey(timeShow); } if (imageSobel.empty()) { cout << "没有进行图像边缘处理" << endl; } else { namedWindow("PicShow"); imshow("PicShow", imageSobel); waitKey(timeShow); } }

//保存图片 void PixImage::PicSave(string name) { if (imageCR.empty()) { cout << "没有进行像素减少处理" << endl; } else cv::imwrite(name + "_像素减少.jpg", imageCR); if (imageBluring.empty()) { cout << "没有进行模糊处理" << endl; } else cv::imwrite(name + "_模糊处理.jpg", imageBluring); if (imageSobel.empty()) { cout << "没有进行图像边缘处理" << endl; } else cv::imwrite(name + "_图像边缘处理.jpg", imageSobel); } ```

图片处理和保存函数,若没有进行相应的处理则输出提示切不保存。

```c++

include

include

include

include "imageProcess.h"

using namespace std; //总共要处理照片数量

define picTotal 1

int main() { string path = "E:/images/"; //存储路径 for (int i = 0; i < picTotal; i++) { stringstream ss; string n; ss << i; ss >> n; PixImage image(path+n+".jpg"); image.colorReduce(); image.Bluring(3); image.Sobel(); image.PicShow(); image.PicSave(path + n); } return 0; } ```

图片处理部分主函数,保存图片至相应的路径并加后缀命名指出进行了何种处理。

5、运行结果

5.1 爬虫部分

爬取了1013个不重复的网址以及10035张图片

5.2 图片处理部分

参考文献

  • 网络爬虫技术在云平台上的研究与实现(电子科技大学·刘小云)
  • 主题网络爬虫的研究和实现(武汉理工大学·林捷)
  • 恶意URL检测项目中基于PageRank算法的网络爬虫的设计和实现(北京邮电大学·王晓梅)
  • 基于网络爬虫的数字隐写图像采集系统设计与实现(华中师范大学·王年丰)
  • 分布式网络爬虫技术的研究与实现(哈尔滨工业大学·苏旋)
  • 主题爬虫关键技术研究(哈尔滨工程大学·黄正德)
  • 分布式Web Crawler系统研究与实现(江西理工大学·胡炜)
  • 基于领域的网络爬虫技术的研究与实现(武汉理工大学·谭龙远)
  • 基于Bloom Filter算法的URL去重算法研究及其应用(河南大学·孟慧君)
  • 分布式网络爬虫在农产品搜索系统中的应用与研究(南昌大学·袁龙涛)
  • 面向垂直搜索引擎的聚焦网络爬虫关键技术研究与实现(华中师范大学·陈欢)
  • 分布式网络爬虫技术的研究与实现(哈尔滨工业大学·苏旋)
  • 面向人脸检测的主题网络爬虫系统(重庆大学·杨东权)
  • 面向中小学教育资源的网络爬虫的研究与设计(中央民族大学·郑名达)
  • 主题网络爬虫的研究和实现(武汉理工大学·林捷)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:源码驿站 ,原文地址:https://bishedaima.com/yuanma/35495.html

相关推荐

发表回复

登录后才能评论