【网络爬虫项目】实战知识点
来源:互联网 发布:flexpaper flash.js 编辑:程序博客网 时间:2024/06/05 19:07
【网络爬虫项目】webcrawler
<tips>
"grep" vi下透过文件的文本查找工具
$ grep -i template *.cpp //template 要查找的字符串
一、变长参数表
返回类型 函数名(参数类型1 形参1, 参数类型2 形参2, ...);
#include <stdarg.h>
va_list ap;
va_start(ap, 形参2); //ap, ...前最近的一个参数
va_arg(ap, 类型); //从ap链表获取下一个"类型"为参数,va_arg返回NULL停止
va_end(ap);
二、字符串拆分
"strtok"(3)
#include <string.h>
char * strtok(char *str, char const * delim);
功能:拆分字符串
参数:
"str" 待拆分字符串
"delim" 分隔字符串
返回值:
成功 - 返回一个拆分所得字符串的指针,最后返回 NULL
char str[] = "abc,def.ghi tarena"; //不能是只读存储字符串
char const * delim = ",. ";
char *p = strtok(str, delim); //p->"abc"
abc\0def.ghi tarena
^
p = strtok(NULL, delim); //p->"def"
abc\0def\0ghi tarena
^
p = strtok(NULL, delim); //p->"ghi"
abc\0def\0ghi\0tarena
^
p = strtok(NULL, delim); //p->"tarena"
abc\0def\0ghi\0tarena
^
p = strtok(NULL, delim); //p->"NULL"
-----> "abc" "def" "ghi" "tarena"
QQword 文档。String类成员函数。
<tips>
g++ -c Precompile.h
---> Precompile.h.gch
//后续可省区重复编译头文件的时间,提高效率
三、域名解析
http://www.sina.com.cn:8080/web/index.html
|-协议-|---> 域 名 <---|端口|---> 路径 <---|
|-------> 统一资源定位符(URL) <-------|
http协议,默认的端口号:80
将字符串形式的主机域名,如www.sina.com.cn,转换为数字形势IP地址,如172.168.30.1,的过程叫:"域名解析"。
域名解析服务:DNS,Domain Name Service
域名解析服务器:提供域名解析服务的计算机
"gethostbyname"(3) //一个函数搞定域名解析
#include <netdb.h>
struct hostent *gethostbyname(const char *name); //hostent主机条目
功能:获得网络主机条目(解析字符串域名)
参数:"name" 字符串形式的主机域名
返回值:
成功 - 返回主机信息条目
失败 - 返回 NULL
struct hostent {
char *h_name; /* official name of host */正式主机名
char **h_aliases; /* alias list */别名表(字符指针数组)
int h_addrtype; /* host address type */地址类型IPv4
int h_length; /* length of address */地址长度(字节)
char **h_addr_list; /* list of addresses */地址表
}
在IPv4的情况下,h_addr_list成员的实际类型为 struct in_addr**
/*
+----+ +---------+
h_addr_list --> | * | --> | in_addr |
+----+ +---------+
| * | --> ...
+----+
|NULL| 空指针作为遍历结束条件
+----+
*/
struct sockaddr_in addr;
addr.sin_family = AF_INET; //ipv4
addr.sin_port = htons(80); //端口
addr.sin_addr.s_addr = inet_addr("172.30.8.20"); //--->网络字节序
connect (sockfd, (sockaddr*)&addr, sizeof(addr)); //连接
struct in_addr {
unsigned int s_addr;
...
};
struct sockaddr_in {
...
struct in_addr sin_addr;
};
<tips>
一般返回指针的函数,以返回 NULL 代表失败;
一般返回整数的函数,以返回 0 或者 -1 代表失败。
正式主机名:
ara.sina.com.cn
别名表:
www.sina.com.cn
jupiter.sina.com.cn
地址表:
58.63.236.248
121.14.1.190
四、超文本传输协议(HTTP)
1. HTTP请求格式(流程)
GET /web/index.html HTTP/1.0<\r><\n> //获取访问目录
Host: www.sina.com.cn<\r><\n> //读取服务器主机
Accept: text/html<\r><\n> //接收请求-html文本格式
Connection: Keep-Alive<\r><\n>//对连接的约束-保持执行
User-Agent: Mozilla/5.0<\r><\n> //客户端代理程序:浏览器
Referer: www.sina.com.cn<\r><\n><\r><\n> //确定是否重定向
//---> 输出内容到文件 tmooc.html :
HTTP/1.0 200 OK
Cache-Control: no-cache
Content-Length: 748
Content-Type: text/html
Date: Wed, 11 Jan 2017 12:08:32 GMT
Expires: 0
<html>
<!--
<?xml version="1.0" encoding="UTF-8"?>
<WISPAccessGatewayParam
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://192.168.1.1/xml/WISPAccessGatewayParam.xsd">
<Redirect>
<AccessProcedure>1.0</AccessProcedure>
<AccessLocation></AccessLocation>
<LocationName></LocationName>
<LoginURL>http://192.168.1.1/login?target=xml</LoginURL>
<MessageType>100</MessageType>
<ResponseCode>0</ResponseCode>
</Redirect>
</WISPAccessGatewayParam>
-->
<head>
<title>...</title>
<meta http-equiv="refresh" content="0; url=http://192.168.1.1/login?dst=http%3A%2F%2F%26s%2F">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
</head>
<body>
</body>
</html>
"strcasecmp" //忽略大小写的字符串比较
概念熟记:
// 统一资源定位符(URL)
// 超文本传输协议(HTTP)
// 超文本标记语言(HTML)
奇偶数算法:
int a;
a & 1 == 0; //为偶数
a & 1 == 1; //为奇数
乘法性能优化:
int a;
a * 33 <==> a * 32 + a <==> a << 5 + a;
五、正则表达式 - (此三个函数仅在UnixC才有,windouws没有)
HTML:
... href=" http://www.ycty.org/about/news/78620.html \n" ...
^ ^ ^ ^ ^
| | |<--------------[1]子表达式------------->|
|rm_so|<----------------len---[0]主表达式---------------->|
|<------------------------------------------------------->|
rm_eo
html
href里面链接前后空白字符不确定。
href="\s*\([^ >"]*\)\s*" //匹配各种href后链接地址的【正则表达式】
"href=\"\\s*\\([^ >\"]*\\)\\s*\"" //代码中格式,注意 \
\s
任意空白字符(空格、制表符、换页、换行符、回车符)
*
重复前一个匹配项任意次
[^ >"]
任意匹配不是空格、大于号、双引号的字符
\(
\)
表示子表达式的左右边界
#include <regex.h> //regular expression 正则表达式
"regcomp"(3)
int regcomp(regex_t *preg, const char *regex, int cflags);
功能:编译正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
"regex" 正则表达式字符串地址
"cflags" 0
返回值:
成功 - 返回 0
错误 - 返回错误码
"regexec"(3)
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
功能:执行(匹配)正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
"string" 指向读取到的html的代码形式字符串
"nmatch" regmatch_t定义的存储区数组个数,用于存储主表达式/子表达式
"pmatch[]" regmatch_t定义的存储区数组名
"eflags" 0
返回值:
成功 - 返回 0
错误 - 返回 REG_NOMATCH
typedef struct {
regoff_t rm_so; //从html开始到正则表达式首地址
regoff_t rm_eo; //从html开始到正则表达式尾地址
} regmatch_t; // regmatch_t match[1]; 保存正则表达式的数组
"regfree"(3)
void regfree(regex_t *preg);
功能:释放正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
返回值:
释放一般不会失败。
"regerror"(3)
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
功能:将错误解析为字符串,写入errbuf
参数:
"errcode" regcomp的返回值
"preg" 存储正则表达式的regex_t类型变量地址
"errbuf" 新定义的存放错误信息的数组的地址
"errbuf_size" sizeof (errbuf) 存放错误信息的数组长度
返回值:
成功 - 返回写入数组的错误信息的字符串长度
失败 - 暂无(无需验证失败)
../script/css/style_v2.css
http://www.ycty.org/about/news/78620.html
http://www.chuanke.com/v5189664-208498-1278072.html
http://www.chuanke.com/v5189664-202714-1223438.html
http://www.chuanke.com/v5189664-203119-1228927.html
http://www.ycty.org/about/news/78620.html
./course_v2.html
六、线程类的封装与继承
void* run (void* arg) { ... } //线程过程函数
pthread_creat (&tid, NULL, run, NULL); //线程tid,线程过程函数run
$: thread
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----...
"互斥锁,来避免线程并发冲突" //并发冲突的线程不安全
七、精灵(守护)进程
1. 孤儿进程
2. 独立会话进程组的首进程
3. 不拥有控制终端,三大标准I/O设备都是空设备
4. 永不终止 (随系统的启动而启动,结束而结束)
精灵进程未屏蔽信号的情况下,kill [pid]默认 (15)SIGTEAM 即可杀死。
八、多路I/O "epoll"(7)
1. "创建"多路I/O对象
在系统内核中创建一个可以负责监视多个文件描述符上所发生I/O事件的对象。
"epoll_create1"(2)
#include <sys/epoll.h>
int epoll_create1(int flags);
功能:打开/创建一个多路文件描述符
参数:"flags" 取 0 ,不在函数调用时设置文件描述符个数(代码后可增)
返回值:
成功 - 返回一个多路I/O对象的文件描述符(非负整数)
失败 - 返回 -1,errno被设置
int epoll = epoll_create1 (0);
^
|
多路I/O对象的文件描述符
2. 将需要关注的文件描述符及其事件"添加"到多路I/O对象中
3. "等待"所关注的事件的发生
4. "取消"对某个文件描述符及其事件的关注
5. "关闭"多路I/O对象
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
<tips>
"grep" vi下透过文件的文本查找工具
$ grep -i template *.cpp //template 要查找的字符串
一、变长参数表
返回类型 函数名(参数类型1 形参1, 参数类型2 形参2, ...);
#include <stdarg.h>
va_list ap;
va_start(ap, 形参2); //ap, ...前最近的一个参数
va_arg(ap, 类型); //从ap链表获取下一个"类型"为参数,va_arg返回NULL停止
va_end(ap);
/** 代码演示 - 函数的变长参数表 **/#include <stdio.h>#include <stdarg.h>int sum(int a, int b, ...) { int res = a + b; va_list ap; va_start(ap, b); int x; while((x = va_arg(ap, int)) != -1) res += x; va_end(ap); return res;}void prints(char const * s1, ...) { puts(s1); va_list ap; va_start(ap, s1); char const * sx; while(sx = va_arg(ap, char const *)) puts(sx); va_end(ap);}int main(void) { printf("%d\n", sum(1, 2, -1)); printf("%d\n", sum(1, 2, 3, -1)); printf("%d\n", sum(1, 2, 3, 4, -1)); prints("a", NULL); prints("a", "bc", NULL); prints("a", "bc", "def", NULL); return 0;}
二、字符串拆分
"strtok"(3)
#include <string.h>
char * strtok(char *str, char const * delim);
功能:拆分字符串
参数:
"str" 待拆分字符串
"delim" 分隔字符串
返回值:
成功 - 返回一个拆分所得字符串的指针,最后返回 NULL
char str[] = "abc,def.ghi tarena"; //不能是只读存储字符串
char const * delim = ",. ";
char *p = strtok(str, delim); //p->"abc"
abc\0def.ghi tarena
^
p = strtok(NULL, delim); //p->"def"
abc\0def\0ghi tarena
^
p = strtok(NULL, delim); //p->"ghi"
abc\0def\0ghi\0tarena
^
p = strtok(NULL, delim); //p->"tarena"
abc\0def\0ghi\0tarena
^
p = strtok(NULL, delim); //p->"NULL"
-----> "abc" "def" "ghi" "tarena"
/** 代码演示 - 字符串拆分 .c **/#include <stdio.h>#include <stdlib.h>#include <string.h>void split(char const * s, char const * delim) {char * str = (char *)malloc(strlen(s)+1);strcpy(str, s);char * p;for(p = strtok(str, delim); p; p = strtok(NULL, delim))puts(p);free(str);str = NULL;}int main() {split("172.30.8.20", ".");split("minwei@tarena.cn", ".@");split("HOME=/usr/tarena", "=");return 0;}
/** 代码演示 - 字符串拆分 .cpp **/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <vector>#include <iostream>using namespace std;vector<string> split(char const * s, char const * delim) {vector<string> vs;char * str = (char *)malloc(strlen(s)+1);strcpy(str, s);char * p;for(p = strtok(str, delim); p; p = strtok(NULL, delim))vs.push_back(p);free(str);str = NULL;return vs;}int main() {vector<string> vs = split("172.30.8.20", ".");vector<string>::const_iterator it;for(it = vs.begin(); it != vs.end(); ++it)cout << *it << endl;vs = split("minwei@tarena.cn", ".@");for(it = vs.begin(); it != vs.end(); ++it)cout << *it << endl;vs = split("HOME=/usr/tarena", "=");for(it = vs.begin(); it != vs.end(); ++it)cout << *it << endl;return 0;}"string"类成员函数: //待补齐
QQword 文档。String类成员函数。
<tips>
g++ -c Precompile.h
---> Precompile.h.gch
//后续可省区重复编译头文件的时间,提高效率
"【打印日志的通用格式】"// 按格式来打印日志void Log::printf (int level, char const* file, int line,char const* format, ...) const { if(level >= LEVEL_DBG) { // 格式化时间字符串 char dateTime[32]; time_t now = time (NULL); strftime(dateTime, sizeof(dateTime),"%Y-%m-%d %H:%M:%S", localtime (&now)); fprintf (stdout, "[%s][%s][pid=%d][tid=%lu][%s:%d]\n", dateTime, s_levels[level], getpid (), pthread_self (), file, line); va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); fprintf (stdout, "\n\n"); } if(level >= LEVEL_ERR) exit (EXIT_FAILURE);}
三、域名解析
http://www.sina.com.cn:8080/web/index.html
|-协议-|---> 域 名 <---|端口|---> 路径 <---|
|-------> 统一资源定位符(URL) <-------|
http协议,默认的端口号:80
将字符串形式的主机域名,如www.sina.com.cn,转换为数字形势IP地址,如172.168.30.1,的过程叫:"域名解析"。
域名解析服务:DNS,Domain Name Service
域名解析服务器:提供域名解析服务的计算机
"gethostbyname"(3) //一个函数搞定域名解析
#include <netdb.h>
struct hostent *gethostbyname(const char *name); //hostent主机条目
功能:获得网络主机条目(解析字符串域名)
参数:"name" 字符串形式的主机域名
返回值:
成功 - 返回主机信息条目
失败 - 返回 NULL
struct hostent {
char *h_name; /* official name of host */正式主机名
char **h_aliases; /* alias list */别名表(字符指针数组)
int h_addrtype; /* host address type */地址类型IPv4
int h_length; /* length of address */地址长度(字节)
char **h_addr_list; /* list of addresses */地址表
}
在IPv4的情况下,h_addr_list成员的实际类型为 struct in_addr**
/*
+----+ +---------+
h_addr_list --> | * | --> | in_addr |
+----+ +---------+
| * | --> ...
+----+
|NULL| 空指针作为遍历结束条件
+----+
*/
struct sockaddr_in addr;
addr.sin_family = AF_INET; //ipv4
addr.sin_port = htons(80); //端口
addr.sin_addr.s_addr = inet_addr("172.30.8.20"); //--->网络字节序
connect (sockfd, (sockaddr*)&addr, sizeof(addr)); //连接
struct in_addr {
unsigned int s_addr;
...
};
struct sockaddr_in {
...
struct in_addr sin_addr;
};
<tips>
一般返回指针的函数,以返回 NULL 代表失败;
一般返回整数的函数,以返回 0 或者 -1 代表失败。
/** 代码演示 - 域名解析过程 **/#include <stdio.h>#include <netdb.h>#include <arpa/inet.h>#include <stdlib.h>int main (int argc, char* argv[]) { if (argc < 2) { printf ("用法:%s <主机域名>\n", argv[0]); exit (EXIT_FAILURE); } struct hostent* host = gethostbyname (argv[1]); if (! host) { perror ("gethostbyname"); exit (EXIT_FAILURE); } if (host->h_addrtype == AF_INET) { printf ("正式主机名:\n"); printf ("\t%s\n", host->h_name); printf ("别名表:\n"); char** ppaliases = host->h_aliases; while (*ppaliases) printf ("\t%s\n", *ppaliases++); printf ("地址表:\n"); struct in_addr** ppaddr = (struct in_addr**)host->h_addr_list; while (*ppaddr) printf ("\t%s\n", inet_ntoa (**ppaddr++)); } return 0;}$: dns www.sina.com.cn
正式主机名:
ara.sina.com.cn
别名表:
www.sina.com.cn
jupiter.sina.com.cn
地址表:
58.63.236.248
121.14.1.190
四、超文本传输协议(HTTP)
1. HTTP请求格式(流程)
GET /web/index.html HTTP/1.0<\r><\n> //获取访问目录
Host: www.sina.com.cn<\r><\n> //读取服务器主机
Accept: text/html<\r><\n> //接收请求-html文本格式
Connection: Keep-Alive<\r><\n>//对连接的约束-保持执行
User-Agent: Mozilla/5.0<\r><\n> //客户端代理程序:浏览器
Referer: www.sina.com.cn<\r><\n><\r><\n> //确定是否重定向
/** 代码参见 - **/#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <strings.h> //Uc字符串处理头文件#include <stdio.h>#include <stdlib.h>#include <string.h>int main (int argc, char* argv[]) {if (argc < 3) {printf ("用法:%s <主机IP地址>""<主机域名> [<资源路径>]\n", argv[0]);exit (EXIT_FAILURE);}char const* ip = argv[1];char const* domain = argv[2];char const* path = argc < 4 ? "" : argv[3];int sockfd = socket (PF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror ("socket");exit (EXIT_FAILURE);}struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons (80);if (! inet_aton (ip, &addr.sin_addr)) { //还可以检查ipperror ("inet_aton");exit (EXIT_FAILURE);}if (connect (sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {perror ("connect");exit (EXIT_FAILURE);}char request[1024];sprintf (request, "GET &s HTTP/1.0\r\n""Host: %s\r\n""Accept: */*\r\n""Connection: Keep-Alive\r\n""User-Agent: Mozilla/5.0\r\n""Referer: %s\r\n\r\n", path, domain, domain);if (send (sockfd, request, strlen(request), 0) == -1) {perror ("send");exit (EXIT_FAILURE);}for (;;) {char respond[1024] = {};ssize_t rlen = recv (sockfd, respond, sizeof (respond) - 1, 0);if (rlen == -1) {perror ("recv");exit (EXIT_FAILURE);}if (rlen == 0)break;printf ("%s", respond);}printf("\n");close(sockfd);return 0;}$: http 58.51.150.41 www.tmooc.cn web/index_new.html?tedu > tmooc.html
//---> 输出内容到文件 tmooc.html :
HTTP/1.0 200 OK
Cache-Control: no-cache
Content-Length: 748
Content-Type: text/html
Date: Wed, 11 Jan 2017 12:08:32 GMT
Expires: 0
<html>
<!--
<?xml version="1.0" encoding="UTF-8"?>
<WISPAccessGatewayParam
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://192.168.1.1/xml/WISPAccessGatewayParam.xsd">
<Redirect>
<AccessProcedure>1.0</AccessProcedure>
<AccessLocation></AccessLocation>
<LocationName></LocationName>
<LoginURL>http://192.168.1.1/login?target=xml</LoginURL>
<MessageType>100</MessageType>
<ResponseCode>0</ResponseCode>
</Redirect>
</WISPAccessGatewayParam>
-->
<head>
<title>...</title>
<meta http-equiv="refresh" content="0; url=http://192.168.1.1/login?dst=http%3A%2F%2F%26s%2F">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
</head>
<body>
</body>
</html>
"strcasecmp" //忽略大小写的字符串比较
概念熟记:
// 统一资源定位符(URL)
// 超文本传输协议(HTTP)
// 超文本标记语言(HTML)
奇偶数算法:
int a;
a & 1 == 0; //为偶数
a & 1 == 1; //为奇数
乘法性能优化:
int a;
a * 33 <==> a * 32 + a <==> a << 5 + a;
五、正则表达式 - (此三个函数仅在UnixC才有,windouws没有)
HTML:
... href=" http://www.ycty.org/about/news/78620.html \n" ...
^ ^ ^ ^ ^
| | |<--------------[1]子表达式------------->|
|rm_so|<----------------len---[0]主表达式---------------->|
|<------------------------------------------------------->|
rm_eo
html
href里面链接前后空白字符不确定。
href="\s*\([^ >"]*\)\s*" //匹配各种href后链接地址的【正则表达式】
"href=\"\\s*\\([^ >\"]*\\)\\s*\"" //代码中格式,注意 \
\s
任意空白字符(空格、制表符、换页、换行符、回车符)
*
重复前一个匹配项任意次
[^ >"]
任意匹配不是空格、大于号、双引号的字符
\(
\)
表示子表达式的左右边界
#include <regex.h> //regular expression 正则表达式
"regcomp"(3)
int regcomp(regex_t *preg, const char *regex, int cflags);
功能:编译正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
"regex" 正则表达式字符串地址
"cflags" 0
返回值:
成功 - 返回 0
错误 - 返回错误码
"regexec"(3)
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
功能:执行(匹配)正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
"string" 指向读取到的html的代码形式字符串
"nmatch" regmatch_t定义的存储区数组个数,用于存储主表达式/子表达式
"pmatch[]" regmatch_t定义的存储区数组名
"eflags" 0
返回值:
成功 - 返回 0
错误 - 返回 REG_NOMATCH
typedef struct {
regoff_t rm_so; //从html开始到正则表达式首地址
regoff_t rm_eo; //从html开始到正则表达式尾地址
} regmatch_t; // regmatch_t match[1]; 保存正则表达式的数组
"regfree"(3)
void regfree(regex_t *preg);
功能:释放正则表达式
参数:
"preg" 存储正则表达式的regex_t类型变量地址
返回值:
释放一般不会失败。
"regerror"(3)
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
功能:将错误解析为字符串,写入errbuf
参数:
"errcode" regcomp的返回值
"preg" 存储正则表达式的regex_t类型变量地址
"errbuf" 新定义的存放错误信息的数组的地址
"errbuf_size" sizeof (errbuf) 存放错误信息的数组长度
返回值:
成功 - 返回写入数组的错误信息的字符串长度
失败 - 暂无(无需验证失败)
/** 代码演示 - 利用正则表达式作为标记截取网页中的链接 **/#include <stdio.h>#include <regex.h>#include <stdlib.h>#include <string.h>int main(int argc, char* argv[]) {if (argc < 2) {printf ("用法:%s <HTML文件>\n", argv[0]);exit (EXIT_FAILURE);}FILE* fp = fopen (argv[1], "r");if (! fp) {perror ("fopen");exit (EXIT_FAILURE);}if (fseek (fp, 0, SEEK_END) == -1) {perror ("fseek");exit (EXIT_FAILURE);}long size = ftell (fp);if (size == -1) {perror ("ftell");exit (EXIT_FAILURE);}char* buf = (char*)malloc (size + 1);if (! buf) {perror ("malloc");exit (EXIT_FAILURE);}if (fseek (fp, 0, SEEK_SET) == -1) {perror ("fseek");exit (EXIT_FAILURE);}if (fread (buf, 1, size, fp) != size) {perror ("fread");exit (EXIT_FAILURE);}buf[size] = '\0';fclose (fp);fp = NULL;// 创建正则匹配器regex_t ex;int error = regcomp (&ex, "href=\"\\s*\\([^ >\"]*\\)\\s*\"", 0);if (error) {char errInfo[1024];regerror (error, &ex, errInfo, sizeof (errInfo));printf ("regcomp: %s\n", errInfo);exit (EXIT_FAILURE);}char const* html = buf;regmatch_t match[2]; //[0]主表达式 [1]子表达式// 匹配正则表达式while (regexec (&ex, html, 2, match, 0) != REG_NOMATCH) {html += match[1].rm_so;size_t len = match[1].rm_eo - match[1].rm_so; char* url = (char*)malloc (len + 1);memcpy (url, html, len);url[len] = '\0';printf ("%s\n", url);free (url);// 打印一个链接后html位置要移动到子表达式的后面html += len + match[0].rm_eo - match[1].rm_eo;}// 销毁正则匹配器regfree (&ex);free (buf);buf = NULL;return 0;}$: regex tmooc.html
../script/css/style_v2.css
http://www.ycty.org/about/news/78620.html
http://www.chuanke.com/v5189664-208498-1278072.html
http://www.chuanke.com/v5189664-202714-1223438.html
http://www.chuanke.com/v5189664-203119-1228927.html
http://www.ycty.org/about/news/78620.html
./course_v2.html
六、线程类的封装与继承
void* run (void* arg) { ... } //线程过程函数
pthread_creat (&tid, NULL, run, NULL); //线程tid,线程过程函数run
"线程类的封装":class Thread { //基类public:void start (void) {pthread_creat (&tid, NULL, run, this);}private:static void* run (void* arg) {return ((Thread*)arg)->run ();}virtual void* run (void) = 0;pthread_t m_tid; //线程的属性:线程的tid};class MyThread : public Thread { //子类private:void* run (void) {...} //没有this指针,不依赖对象有否};Thread thread;thread.start ();
/** 代码演示 - 线程类的封装与继承 **/#include <pthread.h>#include <unistd.h>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;class Thread {public:virtual ~Thread (void) {}void start (void) {pthread_create (&m_tid, NULL, run, this);}private:static void* run (void* arg) {return ((Thread*)arg)->run ();}virtual void* run (void) = 0;pthread_t m_tid;};class MyThread : public Thread {public:MyThread (char ch, int ms) : m_ch (ch), m_ms (ms) {}private:void* run (void) {for (;;) {cout << m_ch << flush;usleep (m_ms * 1000);}return NULL;}char m_ch;int m_ms;};int main(void) {MyThread t1 ('+', 500), t2 ('-', 100);t1.start ();t2.start ();getchar ();return 0;}$: g++ thread.cpp -o thread -lpthread
$: thread
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----...
"互斥锁,来避免线程并发冲突" //并发冲突的线程不安全
七、精灵(守护)进程
1. 孤儿进程
2. 独立会话进程组的首进程
3. 不拥有控制终端,三大标准I/O设备都是空设备
4. 永不终止 (随系统的启动而启动,结束而结束)
/** 代码演示 - 精灵(守护)进程 **/#include <unistd.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>int main (void) { pid_t pid = fork (); if (pid == -1) { perror ("fork"); exit (EXIT_FAILURE); } if (pid) exit (EXIT_FAILURE); setsid (); // 设置会话id,独立会话进程组的首进程 int fd = open ("/dev/null", O_RDWR, 0); if (fd != -1) { dup2 (fd, STDIN_FILENO); dup2 (fd, STDOUT_FILENO); dup2 (fd, STDERR_FILENO); } for (;;) { // ... 精灵进程做的事情 } return 0;}$: ps -eaf | grep daemon //查进程
精灵进程未屏蔽信号的情况下,kill [pid]默认 (15)SIGTEAM 即可杀死。
八、多路I/O "epoll"(7)
1. "创建"多路I/O对象
在系统内核中创建一个可以负责监视多个文件描述符上所发生I/O事件的对象。
"epoll_create1"(2)
#include <sys/epoll.h>
int epoll_create1(int flags);
功能:打开/创建一个多路文件描述符
参数:"flags" 取 0 ,不在函数调用时设置文件描述符个数(代码后可增)
返回值:
成功 - 返回一个多路I/O对象的文件描述符(非负整数)
失败 - 返回 -1,errno被设置
int epoll = epoll_create1 (0);
^
|
多路I/O对象的文件描述符
2. 将需要关注的文件描述符及其事件"添加"到多路I/O对象中
struct epoll_event ev; // 创建多路事件对象ev.events = EPOLLIN; // "输入"事件。EPOLLIN | EPOLLOUT 输入输出事件ev.data.fd = STDIN_FILENO; // "输入"文件描述符epoll_ctl (epoll, EPOLL_CTL_ADD, STDIN_FILENO, &ev);// 关注对应事件// epoll_ctl 返回-1代表错误
3. "等待"所关注的事件的发生
struct epoll_event events[10];int fds = epoll_wait (epoll, events, 10, 5000); //5000毫秒,-1是无限时间。将关注的文件描述符对应的事件填到events数组中,并返回该数组有效元素个数,如果没有事件发生,则最多等待5000毫秒。
4. "取消"对某个文件描述符及其事件的关注
struct epoll_event ev; // 创建多路事件对象ev.events = EPOLLIN; // "输入"事件。EPOLLIN | EPOLLOUT 输入输出事件epoll_ctl (epoll, EPOLL_CTL_DEL, STDIN_FILENO, &ev);// 取消关注事件// epoll_ctl 返回-1代表错误
5. "关闭"多路I/O对象
close (epoll); //它也是个文件描述符,所以close通用
/** 代码验证 - 多路I/O对事件的关注和处理 **/#include <stdio.h>#include <sys/epoll.h>#include <unistd.h>#include <stdlib.h>#include <string.h>int main (void) { // 创建多路I/O对象 int epoll = epoll_create1 (0); if (epoll == -1) { perror ("epoll_create1"); exit (EXIT_FAILURE); } // 关注标准输入设备上的输入事件 struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = STDIN_FILENO; if (epoll_ctl (epoll, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1) { perror ("epoll_ctl"); exit (EXIT_FAILURE); } printf ("等待事件...\n"); // 调试信息 struct epoll_event evts[10]; int fds = epoll_wait (epoll, evts, 10, -1); if (fds == -1) { perror ("eopll_wait"); exit (EXIT_FAILURE); } printf ("fds = %d\n", fds); printf ("fd = %d\n", evts[0].data.fd); if (evts[0].events == EPOLLIN) printf ("发生了输入事件...\n"); // 销毁多路I/O对象 close (epoll); return 0;}
/* ------------------------------------------------------------ */
"【Makefile】"#【可复用Makefile】# 1. 赋值给PROJ最终新生成的可执行文件名PROJ = WebCrawler# 2. 赋值给OBJS可执行文件所依赖的所有.o文件OBJS = StrKit.o \ Log.o \ Configurator.o \ MultiIo.o \ PluginMngr.o \ Hash.o \ BloomFilter.o \ Url.o \ UrlQueues.o \ Socket.o \ Thread.o \ DnsThread.o \ SendThread.o \ RecvThread.o \ WebCrawler.o \ Main.o#赋值相当于重命名等号右侧内容CXX = g++LINK = g++RM = rm -rfCFLAGS = -c -Wall -I. -D_DEBUGLIBS = -ldl -lpthread #-levent#【链接】# 以下内容替换规则等同于 宏(#define), $^ 代表依赖项 <==> $(OBJS)$(PROJ): $(OBJS)$(LINK) $^ $(LIBS) -o ../bin/$@#【编译】# .o依赖于.cpp , 此处的 $^ 代表的是依赖文件所有的.cpp.cpp.o:$(CXX) $(CFLAGS) $^#【清理指令】$ make cleanclean:$(RM) ../bin/$(PROJ) $(OBJS) *.gch
/* ------------------------------------------------------------ */
"【.mak】"# 【Makefile 编译动态链接共享库文件】PROJ = DomainLimit.soOBJS = DomainLimit.oCXX = g++LINK = g++RM = rm -rfCFLAGS = -c -fpic -Wall -I. -I../src -D_DEBUG$(PROJ): $(OBJS)$(LINK) -shared $^ -o $@.cpp.o:$(CXX) $(CFLAGS) $^clean:$(RM) $(PROJ) $(OBJS) *.gch
/* ------------------------------------------------------------ */
"【mkall】"#!/bin/bashmake -f MaxDepth.mak cleanmake -f MaxDepth.makmake -f DomainLimit.mak cleanmake -f DomainLimit.makmake -f HeaderFilter.mak cleanmake -f HeaderFilter.makmake -f SaveHTMLToFile.mak cleanmake -f SaveHTMLToFile.makmake -f SaveImageToFile.mak cleanmake -f SaveImageToFile.makexit 0
/* ------------------------------------------------------------ */
"【构建脚本】"$: make clean$: make"【构建插件】"$: mkall"【运行】"$: cd ../bin$: WebCrawler -d // 精灵模式运行$: cd ../download // 爬虫抓取文件存放位置
0 0
- 【网络爬虫项目】实战知识点
- Python大型网络爬虫项目开发实战
- Python网络爬虫实战项目代码大全
- Python网络爬虫实战项目代码大全
- Python网络爬虫实战项目代码大全
- Python网络爬虫实战项目大全!
- 网络爬虫相关知识点
- Python3 大型网络爬虫实战 — 给 scrapy 爬虫项目设置为防反爬
- Python实战:Python网络爬虫
- python实战之网络爬虫
- 网络爬虫项目搜集
- 网络爬虫项目
- python爬虫实战小项目
- Python3 大型网络爬虫实战 003 — scrapy 大型静态图片网站爬虫项目实战 — 实战:爬取 169美女图片网 高清图片
- Python3 大型网络爬虫实战 004 — scrapy 大型静态商城网站爬虫项目编写及数据写入数据库实战 — 实战:爬取淘宝
- Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
- Android实战——jsoup实现网络爬虫,糗事百科项目的起步
- Android实战——jsoup实现网络爬虫,糗事百科项目的起步
- MongoDB基础学习
- 蓝桥杯 历届试题 买不到的数目 解题报告(完全背包,数论)
- java基础学习笔记之String、StringBuffer、StringBuilder
- 拖动图片到 Python 脚本,自动生成 Markdown 格式链接
- JAVA properties文件的读取
- 【网络爬虫项目】实战知识点
- hdoj2149Public Sale
- android CCD
- Nginx运行日志自动切割
- ai1835-宇航员 C语言 暴力求解
- UE4入门学习1:环境搭建
- 【动态规划】#1038 : 01背包
- tomcat7在eclipse中,调试时断点频繁停在threadpoolexecutor
- Flask on SAE