C++实现图片爬虫
代码是从B站学的,所以并不是很原创
实现思路
- 输入需要爬取的网址加入网址队列;
- 使用BFS:
- 获取网址队列队首中的网址,并从队列中弹出,解析出网址中的主机名以及文件(html、jpg等文件)存放的目录;
- 通过解析出的解析出的信息使用Socket套接字建立连接,发送GET请求;
- 获取GET得到的HTML文件内容,并使用正则表达式获得其中关于JPG(或者其他格式的图片)的链接和跳转链接分别存于两个vector数组;
- 遍历存放图片链接的vector数组,建立连接,使用GET方法获取JPG图片,存放至文件夹,遍历结束后清空数组(因为当前html页面中的图片都获取了);
- 遍历存放跳转链接的vector数组,如果没有获取过该网址的图片(使用map对爬过的网址进行标记)则加入到网址队列。
实现代码
广度优先遍历该网站 BFS
BFS需要获得起始网址的链接。
void bfs(string beginUrl)
{
queue<string>q;
q.push(beginUrl);
while (!q.empty())
{
string cur = q.front();
mp[cur]++;
q.pop();
char tmp[800];
strcpy(tmp, cur.c_str());
analyUrl(tmp); //得到主机名和子链接
preConnect(); //连接服务器GET发送请求图片数据
HandleHTML(); //获取并解析HTML文件中的图片和跳转链接
for(int i=0;i<photoUrl.size();i++)
OutImage(photoUrl[i]); //获取每个图片
photoUrl.clear();
for(int i=0;i<comUrl.size();i++)
if (mp[comUrl[i]] == 0) //将跳转链接加入到队列
q.push(comUrl[i]);
comUrl.clear();
}
}
处理HTML文本 HandleHTML
调用recv函数接收HTML文本,并调用函数进行解析
void HandleHTML()
{
int n;
char buf[1024];
//if (recv(sock, buf, sizeof(buf) - 1, 0) == SOCKET_ERROR) cout << "error";
while ((n = recv(sock, buf, sizeof(buf) - 1, 0)) > 0)
{
buf[n] = '\0';
allHtml += string(buf);
}
regexGetimage(allHtml);
regexGetcom(allHtml);
}
解析网址 analyUrl
analyUrl需要参数url即存放待解析的网址数组的地址
使用strstr判断其中是否有"http:// "的信息,如果没有则结束,如果有则从http:// 的下一个位置开始(所以pos要+7)使用sscanf读取到’/'之前的内容即host,以及之后的内容即文件存放的位置othPath。
bool analyUrl(char* url)
{
char* pos = strstr(url, "http://");
if (pos == NULL) return NULL;
else
{
pos += 7;
}
sscanf(pos, "%[^/]%s", host, othPath);
cout << "host: " << host << " repath: " << othPath << endl;
return true;
}
读取HTML中的图片链接 regexGetimage
其中allHTML为获得的HTML文本内容,参考正则表达式的使用,图片链接是 src=“链接” 的形式,所以正则表达式为"src="“开头(’'反斜杠是转义符),其中的链接应以.jpg结尾,”.?“中.为匹配除”\n"之外的任何单个字符,*是多个字符,最后?是最短匹配即可,那么从allHTML头开始至结尾使用pattern模式进行匹配,mat[0]为匹配上的串,mat[1]为"(.?.jpg)"中匹配上的串,跳转到mat[0]的下一个位置继续匹配。
正则表达式的使用在文后附上参考博客链接
void regexGetimage(string& allHtml)
{
smatch mat;
regex pattern("src=\"(.*?\.jpg)\"");
string::const_iterator start = allHtml.begin();
string::const_iterator end = allHtml.end();
while (regex_search(start, end, mat, pattern))
{
string msg(mat[1].first, mat[1].second);
//photoUrl.push_back(msg);
photoUrl.push_back("http:"+msg); //有的网站html文件中图片不在本网站,链接前又没有HTTP://
start = mat[0].second;