Socket网络编程--网络爬虫(4)
上一小节我们已经实现了获取博客园最近博客的200页里面的用户名,并保存在一个map中。一开始是想通过这个用户名然后构造一个博客地址。然后在这个地址中查找心得用户名,但是后来发现这个的效率不是很高,虽然部分博客会引用别人的博客,也有机率会留有原博客的地址,这样我们可以爬取的到新的用户名。效率是不高。最后我发现博客园的关注和粉丝这个功能用于查找心得用户名很管用。只要该用户在博客园活跃过一段时间就或多或少会有粉丝或关注过某人。(不是有个说法:通过7个人能认识世界上任意一个人)所以这种做法应该是可行的。下面送上一张一开始就画好的框架。有些可能最后的实现跟图中不是很相同。
理论上这样是可以获取得到,但是在实践的时候才知道,原来没有登录的用户是访问不了别人的粉丝和关注,没想到这个美好的想法就这样没了。这可怎么办呢?(如果有知道的还请告诉我呀。)
由于种种原因,最后是实现不了这种循环爬取的效果了。都怪写之前没有好好试验一下,也可能是可以完成,只是自己太弱的原因了。只能提供几个可以获取的用户名的地址。因为达不到那种迭代的效果我就不写。真是太不好意思了。(http://www.cnblogs.com/cate/all/1 ~ http://www.cnblogs.com/cate/all/200、http://www.cnblogs.com/comment/1 ~ http://www.cnblogs.com/comment/200)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <regex.h>//正则表达式
#include <map>
#include <queue>
#include <string>
#include <iostream> using namespace std;
#define BUF_SIZE 512 struct URL
{
char host[];
char url[];//除去域名后的url
};
int reptile_regex(char * buf,char *pattern,map<string,int> & user);
int createSocket(char *hostname,int port);
int closeSocket(int sockfd);
int sendHttpRequest(int sockfd,struct URL url);
int recvHttpRespond(int sockfd,char *ch);
int reptile_regex_url(char * buf,char *pattern,map<string,int> & user,queue<string> & qstr,int start); int main(int argc,char *argv[])
{
int sockfd;
char ch[];//100k
char pattern_user[]={};
char pattern_url[]={};
struct URL url;
string str;
map<string,int> user;//第一个是用户名,第二个保存被加入的次数
queue<struct URL> qurl;
queue<string> qstr; //http://www.cnblogs.com/sitehome/p/1 - 200 //最新博客的200篇
//初始化用户名
for(int i=;i<=;++i)
{
strcpy(url.host,"www.cnblogs.com");
strcpy(url.url,"/sitehome/p/");
char pch[];
sprintf(pch,"%d",i);
strcat(url.url,pch);
strcat(url.url,"/");
cout<<"当前正在判断:"<<url.host<<url.url<<endl;
sockfd=createSocket(url.host,);
sendHttpRequest(sockfd,url);
recvHttpRespond(sockfd,ch);
strcpy(pattern_user,"http://www.cnblogs.com/[[:alnum:][:cntrl:]\\-\\_]*");
reptile_regex_url(ch,pattern_user,user,qstr,); closeSocket(sockfd);
}
//一开始以为是只要创建一次socket然后每次都可以进行send&recv的。但是后来测试好像不行,每次都要进行一次socket的创建
while()
{
while(!qstr.empty())
{
//构造用户的粉丝地址和关注地址
strcpy(url.host,"home.cnblogs.com");
strcpy(url.url,"/u/");
strcat(url.url,qstr.front().c_str());
qurl.push(url);//加入粉丝/关注地址
cout<<"粉丝/关注地址:"<<url.host<<url.url<<endl;
qstr.pop();
}
while(!qurl.empty())
{
url=qurl.front();
qurl.pop();
cout<<"现在正在判断:";
cout<<url.host<<url.url<<endl;
//将获取到的地址进行再次获取用户名
sockfd=createSocket(url.host,);
sendHttpRequest(sockfd,url);
recvHttpRespond(sockfd,ch);
//查看源代码发现地址居然不是想象中的http://home.cnblogs.com/u/用户名,而是/u/用户名
strcpy(pattern_user,"/u/[[:alnum:][:cntrl:]\\-\\_]*");
reptile_regex_url(ch,pattern_user,user,qstr,);
closeSocket(sockfd);
}
}
return ;
} //第一个参数是要匹配的字符串,第二个参数是匹配的规则
int reptile_regex_url(char * buf,char *pattern,map<string,int> & user,queue<string> & qstr,int start)
{
size_t nmatch=;
regmatch_t pm[];
regex_t reg;//正则表达式指针
char * str;
char ch[];
int i,j,k;
str=buf;
regcomp(®,pattern,REG_EXTENDED);//编译匹配模式
while(regexec(®,str,nmatch,pm,)!=REG_NOMATCH)
{
i=pm[].rm_so+start;
k=;
memset(ch,,sizeof(ch));
for(j=i;j<pm[].rm_eo;++j)
{
if(str[j]!=0x01) //ctrl-v ctrl-a
{
ch[k++]=str[j];
}
}
string st(ch);
if(user[st]==)
{
cout<<"新加入的用户名:"<<st<<endl;
qstr.push(st);
}
user[st]++;
str=str+pm[].rm_eo;
}
regfree(®);
return ;
} int closeSocket(int sockfd)
{
close(sockfd);
return ;
} int createSocket(char *hostname,int port)
{
struct sockaddr_in servAddr;
struct hostent * host;
int sockfd;
host=gethostbyname(hostname);
if(host==NULL)
{
perror("dns 解析失败");
}
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
servAddr.sin_port=htons(port);
bzero(&(servAddr.sin_zero),); sockfd=socket(AF_INET,SOCK_STREAM,);
if(sockfd==-)
{
perror("socket 创建失败");
} if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
}
return sockfd;
} int sendHttpRequest(int sockfd,struct URL url)
{
char sendBuf[BUF_SIZE];
int sendSize;
//构建一个http请求
sprintf(sendBuf,"GET %s HTTP/1.1 \r\nHost: %s \r\nConnection: Close \r\n\r\n",url.url,url.host);
printf("%s\n",sendBuf);
if((sendSize=send(sockfd,sendBuf,BUF_SIZE,))==-)
{
perror("send 失败");
}
return ;
} int recvHttpRespond(int sockfd,char *ch)
{
char recvBuf[BUF_SIZE];
int recvSize;
//获取http应答信息
memset(recvBuf,,sizeof(recvBuf));
memset(ch,,sizeof(ch));
while(recvSize=recv(sockfd,recvBuf,BUF_SIZE,)>)
{
recvBuf[recvSize-]=;
strcat(ch,recvBuf);
memset(recvBuf,,sizeof(recvBuf));
}
return ;
}
========2014年9月2日更新===========
今天找到一个解决的办法了。原来是使用cookie来解决,就是在一个请求头Header中增加一个Cookie端,具体的实现思路可以参考这篇博客: http://www.cnblogs.com/fengfenggirl/p/zhihu_shenhuifu.html 在这里先记录下来,下次如果要实现就可以参照这个思路了。
本文地址: http://www.cnblogs.com/wunaozai/p/3903545.html
Socket网络编程--网络爬虫(4)的更多相关文章
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...
- UNIX网络编程——网络IPC:套接字
UNIX网络编程——网络IPC:套接字 Contents 套接字接口 套接字描述符 寻址 字节序 地址格式 地址查询 绑定地址 建立连接 数据传输 套接字选项 带外数据 UNIX域套接字 使用套接字的 ...
- Socket网络编程--网络爬虫(1)
我们这个系列准备讲一下--网络爬虫.网络爬虫是搜索引擎系统中十分重要的组成部分,它负责从互联网中搜集网页,采集信息,这些网页信息用于建立索引从而为搜索引擎提供支持,它决定着整个引擎系统的内容是否丰富, ...
- 网络编程—网络基础概览、socket,TCP/UDP协议
网络基础概览 socket概览 socket模块—TCP/UDP的实现 TCP/UDP总结 网络基础概览 osi七层协议各层主要的协议 # 物理层传输电信号1010101010 # 数据链路层,以太网 ...
- linux网络编程--网络编程的基本函数介绍与使用【转】
本文转载自:http://blog.csdn.net/yusiguyuan/article/details/17538499 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览 ...
- python网络编程——网络IO模型
1 网络IO模型介绍 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-bl ...
- JAVA基础知识之网络编程——-网络通信模型(IO模型)
<Unix网络编程:卷1>中介绍了5中I/O模型,JAVA作为运行在宿主机上的程序,底层也遵循这5中I/O模型规则.这5中I/O模型分别是: 阻塞式IO 非阻塞式IO I/O复用 信号驱动 ...
- UNIX网络编程——网络I/O模型
在学习UNIX网络编程的时候.一開始分不清 同步 和 异步,所以还是总结一下,理清下他们的差别比較好. IO分类 IO依据对IO的调度方式可分为堵塞IO.非堵塞IO.IO复用.信号驱动IO.异步IO. ...
- Socket网络编程--网络爬虫(2)
上一小节,我们实现了下载一个网页.接下来的一步就是使用提取有用的信息.如何提取呢?一个比较好用和常见的方法就是使用正则表达式来提取的.想一想我们要做个什么样的网络爬虫好呢?我记得以前好像博客园里面有人 ...
随机推荐
- RelativeLayout的16种特有属性
*相对于兄弟控件的位置属性 android:layout_above="@id/center_btn"处于某一个控件的上方 android:layout_below="@ ...
- sharc dsp 学习记录1---2014-07-30
从今天开始记录学习sharc dsp过程中的点点滴滴吧. DPI:Digital Peripheral Interface DAI:Digital Audio Interface SHARC ...
- C++雾中风景番外篇:理解C++的复杂声明与声明解析
在学习C系列语言的过程之中,理解C/C++的复杂声明一直是初学者很困扰的问题.笔者初学之时也深受困扰,对很多规则死记硬背.后续在阅读<C专家编程>之后,尝试在编译器的角度来理解C/C++的 ...
- 机器学习 支持向量机(SVM) 从理论到放弃,从代码到理解
基本概念 支持向量机(support vector machines,SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器.支持向量机还包括核技巧,这使它成为实质上的非线性分 ...
- C# 基于 adb 控制安卓
我司呢,有深信服网关. 我们做项目,日常是比较“清闲”的,所以呢,深信服让你没有办法愉快的使用电脑, 但是手机是可以连外网和外面的 wifi 的,所以我们就玩手机,但是玩手机这么明显会被 Leader ...
- 安卓工作室 android studio文件和代码模板,以及汉化出错问题
安卓工作室 android studio文件和代码模板,以及汉化出错问题 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313 ...
- 用单片机控制LED灯(项目)
#include <reg52.h> #define uchar unsigned char sbit LED_RED = P2^; sbit LED_GREEN = P2^; sbit ...
- 2016年3月16日Android学习笔记
1.Jdk1.7以上switch语句中才能用字符串,在Android Studio中我改正了jdk的版本为1.8,但是还是出同样的错误,原来我用的sdk版本是4.4的,改成5的就没有问题了. 2.引入 ...
- SVN解决本地版本控制与服务器版本冲突问题
最近经常遇到一个冲突问题,svn服务器已经没有这个文件,本地也没有这个文件,但是你提交代码的时候svn会显示冲突,也就是说本地svn仍然在管理着这个文件. 解决办法:在相应的目录下新建一个名字一样的文 ...
- iOS主流机型更新
主流机型更新后,舍弃了原有的iPhone 4 ,iPhone 4s, iPhone 5 ,iPhone 5s.增加了iPhone X,iPhone 8和iPhone 8 plus. 总体上屏幕趋于一个 ...