python实现curl,php_curl
简单分析C之卷曲模块同服务器端编程语言(专业超文本预处理器的缩写)的卷曲和大蟒的pycurl模块的关系- CL .唐-博客园
简单分析C之卷曲模块同服务器端编程语言(专业超文本预处理器的缩写)的卷曲和大蟒的pycurl模块的关系缘起:以前一直喜欢用scrapy做爬虫,并且实践效果也很好,后来由于单位让自己写一套分布式爬虫(python实现),替代公司原有的爬虫(php实现),大致用于实践后,发现效果是比原来的效果好,原来能做配置的网站20个里能配置10个,现在20个里能配置16个,分析原因,是架构设计方面有那么一点点扩充性,在大致架构不变的基础上,可进行有限的扩展,而其实实现的原理都是通过卷曲来实现的。
服务器端编程语言(专业超文本预处理器的缩写)的卷曲,是在服务器端编程语言(专业超文本预处理器的缩写)发布程序的外面的(外观的简写)文件中,作为一个服务器端编程语言(专业超文本预处理器的缩写)自带的支持,需要改写服务器端编程语言(专业超文本预处理器的缩写)的配置文件,修改php.ini,将;extension=php_curl.dll前的分号去掉。
大蟒的皮库尔,不是大蟒自带的支持程序,python在做爬虫一般都是用urllib,urllib2,twisted等,比较少的使用皮考尔。安装略。
c的卷曲,是前面2个语言的卷曲父程序,是c的卷曲才有了服务器端编程语言(专业超文本预处理器的缩写)的卷曲和大蟒的皮库尔,同时,python的pycurl文档说明了只实现了部分功能,即是一个c的卷曲的阉割版。泪奔,原来用了那么长时间的东西,连冰山一角都没触碰,或者大蟒的pycurl也只是会用其中的一个或少数几个功能。
如何用:
C的卷曲:
#包含标准视频
#包含卷曲/卷曲。h
int main(void)
卷曲*卷曲;
库尔科德水库
curl=curl_easy_init()。
如果(卷曲){
/*首先设置即将接收我们帖子的URL .这个统一资源定位器可以
如果https://URL应该接收
数据。*/
curl_easy_setopt(curl,CURLOPT_URL, http://postit。举例。com/moo。CGI’);
/*现在指定发布数据*/
curl_easy_setopt(curl,CURLOPT_POSTFIELDS, name=Daniel project=curl );
/*执行请求,res会得到返回码*/
RES=curl _ easy _ perform(curl);
/*总是清理*/
curl _ easy _ clean up(卷曲);
返回0;
}php的卷曲:
?服务器端编程语言(专业超文本预处理器的缩写)
$ c=curl _ init();
curl_setopt($c,CURLOPT_URL, http://www .百度一下。com’);
$ data=curl _ exec($ c);
curl _ close($ c);
echo $ c;
?大蟒的pycurl:
导入pycurl
定义主体(缓冲区):
打印缓冲器
c=pycurl .卷曲度()
西托普(pycurl .网址,‘http://www.baidu.com/)
西托普(pycurl .WRITEFUNCTION,主体)
c。执行()
主要原理:
丙:
使用到的数据结构:
typedef void卷曲;/*当初始化什么的时候只是一个空的类型*/
结构会话句柄{
结构名称十进位计数制
struct Curl _ multi * multi/*用于多线程处理*/
struct Curl _ one _ easy * multi _ pos/*如果非空,指向它的位置
在多控制结构的协助下
在搬迁中。*/
struct Curl _ share * share/* Share,处理全局变量互斥*/
结构句柄数据请求数据;/*请求特定数据*/
结构用户定义的集;/*由网络库用户设置的值,用于setopt等*/
结构动态变化;/*可能修改了用户定义的数据*/
struct CookieInfo * cookies/*从文件和服务器读取的cookie */
结构进度进度;/*对于所有的进度表数据*/
结构UrlState状态;/*用于状态信息的字段的结构
其他动态目的*/
struct PureInfo info/*统计、报告和信息数据*/
# if defined(CURL _ DOES _ CONVERSIONS)defined(HAVE _ ICONV)
iconv _ t outbound _ cd/*用于转换为网络编码*/
iconv _ t inbound _ cd/*用于从网络编码转换*/
iconv _ t utf8 _ cd/*用于转换为UTF8 */
#endif /* CURL_DOES_CONVERSIONS有_ICONV */
无符号int magic/*设置为CURLEASY_MAGIC_NUMBER */
用户定义的结构{
文件*错误/*此处显示标准错误用户数据*/
void * debugdata/*将传递给fdebug的数据*/
字符*错误缓冲区;/*(静态)在此存储失败消息*/
长代理端口;/*如果非零,默认情况下使用此端口号。如果
代理字符串以":[端口]"为特征,用户将覆盖它
这个。*/
/**一下省略10000行- -**/
};
使用的方法1:
1.初始化卷曲,得到会话句柄结构体空间
卷曲*卷曲_简易_初始化(空)
库尔科德水库
结构会话句柄*数据
/*确保我们启动了全局加密套接字协议层
如果(!已初始化){
RES=CURL _ GLOBAL _ init(CURL _ GLOBAL _默认值);
if(res) {
/*全局初始化失败,不返回任何内容*/
DEBUGF(fprintf(stderr, Error:curl _ global _ init失败\ n );
返回空
/*目前为止,我们使用curl_open()和未定义的URL */
res=Curl_open(数据);
if(res!=CURLE_OK) {
DEBUGF(fprintf(stderr, Error:Curl _ open失败\ n );
返回空
返回数据;
}方法2.
设置参数:
CURL代码CURL _ easy _ setopt(CURL * CURL,CURLoption标记,)
va _ list参数
结构会话Handle * data=curl
CURLcode ret
如果(!卷曲)
返回CURLE _ BAD _ FUNCTION _自变量
va_start(arg,tag);
ret=Curl_setopt(data,tag,arg);
va _ end(arg);
返回浸水使柔软
Curl代码Curl _ set opt(结构会话句柄*数据,CURLoption选项,
虚拟设备列表参数)
char * argptr
CURLcode result=CURLE _ OK
#ifndef CURL_DISABLE_HTTP
curl _ off _ t bigsize
#endif
开关(可选){
案例CURLOPT_DNS_CACHE_TIMEOUT:
数据集。DNS _ cache _ time out=va _ arg(param,long);
打破;
案例CURLOPT_DNS_USE_GLOBAL_CACHE:
long use_cache=va_arg(param,long);
如果(使用缓存)
Curl_global_host_cache_init().
数据集。global _ DNS _ cache=(bool)(0!=use _ cache);
打破;
case CURLOPT_SSL_CIPHER_LIST:
/*设置我们希望在加密套接字协议层连接中使用的密码列表*/
result=Curl _ sets tropt(数据集。str[字符串SSL密码列表],
va_arg(param,char *);
打破;
案例CURLOPT_RANDOM_FILE:
*这是包含要播种的随机数据的文件的路径名
*随机加密套接字协议层的东西。该文件仅用于读取。
result=Curl _ sets tropt(数据集。str[STRING _ SSL _ RANDOM _ FILE],
va_arg(param,char *);
打破;
case CURLOPT_EGDSOCKET:
*熵收集守护程序套接字路径名
result=Curl _ sets tropt(数据集。str[字符串_ SSL _ EGD套接字],
va_arg(param,char *);
打破;
case CURLOPT_MAXCONNECTS:
*设置最大同时活动连接的绝对数量
* libcurl允许有。
result=Curl_ch_connc(data,data- state.connc,va_arg(param,long));
打破;
案例CURLOPT _禁止_重用:
*传输完成后,它不能被
*后续转让,但应立即关闭。
数据集。reuse _ body=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_FRESH_CONNECT:
*此传输不应使用先前缓存的连接,但是
*应采用全新的连接方式!
data- set.reuse_fresh=(bool)(0!=va_arg(param,long));
打破;
case CURLOPT_VERBOSE:
*详细意味着infof()调用提供了大量关于
*连接和传输程序以及内部选择。
data- set.verbose=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_HEADER:
*设置在通用数据输出流中包含标题。
数据集。include _ header=(bool)(0!=va_arg(param,long));
打破;
case CURLOPT_NOPROGRESS:
*关闭内部支持的进度表
数据集。hide _ progress=(bool)(0!=va_arg(param,long));
if(data- set.hide_progress)
数据-进度。flags =PGRS _ HIDE;
其他
数据-进度。flags=~ PGRS _ HIDE;
打破;
case CURLOPT_NOBODY:
*不要在输出数据流中包含正文部分。
data- set.opt_no_body=(bool)(0!=va_arg(param,long));
if(data- set.opt_no_body)
/*在超文本传送协议行话中,这意味着使用头请求*/
数据集。http req=http req _ HEAD
打破;
case CURLOPT_FAILONERROR:
*不要输出=300错误代码HTML-页面,而是只输出
*返回错误。
数据集。http _ fail _ on _ error=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_UPLOAD:
案例CURLOPT_PUT:
*我们要向远程主机发送数据。如果这是HTTP,那就等于
*使用放请求。
数据集。上传=(bool)(0!=va_arg(param,long));
如果(数据集。上传)
/*如果这是HTTP,则需要放来"上传"*/
数据集。http req=http req _ PUT
打破;
case CURLOPT_FILETIME:
*尝试获取远程文档的文件时间。时间会
*稍后(可能)使用curl_easy_getinfo()变得可用。
data- set.get_filetime=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT _ FTP _ CREATE _ MISSING _ DIRS:
*一个文件传送协议选项,修改上传以在上创建缺失的目录
*服务器。
数据集。FTP _ create _ missing _ dirs=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_FTP_RESPONSE_TIMEOUT:
*指定文件传送协议响应速度的文件传送协议选项
*在被视为故障之前获得。
数据集。FTP _ response _ time out=va _ arg(param,long)* 1000;
打破;
case CURLOPT_DIRLISTONLY:
*将命令更改为要求列表的选项
*只有,没有文件信息细节。
数据集。FTP _ list _ only=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_APPEND:
*我们希望上传并追加到现有文件中。
data- set.ftp_append=(bool)(0!=va_arg(param,long));
打破;
case CURLOPT _ FTP _方法:
*如何通过文件传送协议访问文件。
数据集。FTP _ file方法=(curl _ FTP file)va _ arg(param,long);
打破;
案例CURLOPT_NETRC:
*解析$HOME/.用于保存站点的用户名和密码文件
数据集。use _ NETRC=(enum CURL _ NETRC _ OPTION)va _ arg(param,long);
打破;
案例CURLOPT_NETRC_FILE:
*使用此文件而不是$HOME/.用于保存站点的用户名和密码文件
result=Curl _ sets tropt(数据集。str[STRING _ NETRC _ FILE],
va_arg(param,char *);
打破;
case CURLOPT_TRANSFERTEXT:
*此选项以前被命名为FTPASCII .重命名以使用
*不仅仅是FTP,还有更多协议。
*使用ASCII(而不是二进制)传输。
数据集。prefere _ ascii=(bool)(0!=va_arg(param,long));
打破;
case CURLOPT_TIMECONDITION:
*设置超文本传送协议时间条件。这必须是中的定义之一
* curl/curl.h头文件。
数据集。时间条件=(curl _ time cond)va _ arg(param,long);
打破;
case CURLOPT_TIMEVALUE:
*这是要用与远程文档进行比较的值
*用CURLOPT_TIMECONDITION设置的方法
数据集。时间值=(time _ t)va _ arg(param,long);
打破;
case CURLOPT_SSLVERSION:
*设置要尝试连接的显式加密套接字协议层版本,如某些加密套接字协议层
*实现是蹩脚的。
数据集。SSL。version=va _ arg(param,long);
打破;
#ifndef CURL_DISABLE_HTTP
case CURLOPT_AUTOREFERER:
*如果卷曲跟随位置,则打开设置的自动推荐人.
数据集。http _ auto _ referer=(bool)(0!=va_arg(param,long));
打破;
case CURLOPT_ENCODING:
*在接受编码标头的值处使用的字符串。
*如果编码设置为"",我们将使用一个接受编码标头,它
*包含我们支持的所有编码。
*如果编码设置为空,我们不会发送接受编码标头
*并忽略接收到的内容编码报头。
argptr=va_arg(param,char *);
result=Curl _ sets tropt(数据集。str[字符串编码],
(argptr!*argptr)?
(char *)ALL _ CONTENT _ ENCODINGS:arg ptr);
打破;
case CURLOPT_FOLLOWLOCATION:
*跟随位置:HTTP-server上的头提示。
数据集。http _ follow _ location=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_UNRESTRICTED_AUTH:
*跟踪位置时发送验证(用户密码),即使
*主机名已更改。
数据集。http _ disable _ hostname _ check _ before _ authentic ation=
(bool)(0!=va_arg(param,long));
打破;
case CURLOPT_MAXREDIRS:
*允许卷曲跟随位置的最大跳数:
*标题。这应该主要用于检测永无止境的循环。
数据集。maxredirs=va _ arg(param,long);
打破;
案例CURLOPT_POST301:
*遵守RFC 2616/10.3.2,重新提交帖子作为301之后的帖子。
data- set.post301=(bool)(0!=va_arg(param,long));
打破;
案例CURLOPT_POST:
/*这个选项还有用吗?是的,什么时候
不使用CURLOPT_POSTFIELDS,POST数据从
回调!*/
if(va_arg(param,long)) {
数据集。http req=http req _ POST
数据集。opt _ no _ body=FALSE/*这是隐含的*/
其他
数据集。http req=http req _ GET
打破;
case CURLOPT_COPYPOSTFIELDS:
*包含邮政数据的字符串。使curl HTTP POST .即使它为空。
*如果需要,必须在之前设置CURLOPT_POSTFIELDSIZE
* CURLOPT_COPYPOSTFIELDS并且以后不会更改。
argptr=va_arg(param,char *);
如果(!参数指针 数据集。postfieldsize==-1)
result=Curl _ sets tropt(数据集。str[STRING _ COPYPOSTFIELDS],arg ptr);
否则{
*检查请求的长度没有溢出尺寸_t类型。
if ((data- set.postfieldsize 0)
((sizeof(curl_off_t)!=sizeof(size_t))
(数据集。post fieldsize(curl _ off _ t)((size _ t)-1))))
result=CURLE _ OUT _ OF _ MEMORY
否则{
char * p;
(void)Curl _ sets tropt(数据集。str[STRING _ COPYPOSTFIELDS],NULL);
/*即使在大小==0时也分配。这满足了可能的需要
稍后地址比较以检测COPYPOSTFIELDS模式,以及
标记使用后置字段,而不是读取函数或
表单数据。
p=malloc((size _ t)(数据集。postfieldsize?数据集。post field size:1));
如果(!p)
result=CURLE _ OUT _ OF _ MEMORY
否则{
如果(数据集。postfieldsize)
memcpy(p,argptr,数据集。post fieldsize);
数据集。str[STRING _ COPYPOSTFIELDS]=p;
数据集。发布字段=数据集。str[STRING _ COPYPOSTFIELDS];
数据集。http req=http req _ POST
打破;
案例CURLOPT_POSTFIELDS:
*和上面一样,但是使用静态数据而不是复制它。
数据集。post fields=va _ arg(param,void *);
/*释放旧的复制数据。*/
(void)Curl _ sets tropt(数据集。str[STRING _ COPYPOSTFIELDS],NULL);
数据集。http req=http req _ POST
打破;
case CURLOPT_POSTFIELDSIZE:
数据交换数据的大小防止网络库对斯特伦()做
*搞清楚。启用二进制发布。
bigsize=va_arg(param,long);
如果(数据集。post fieldsize bigsize
数据集。post字段==数据集。str[STRING _ copy post字段]){
/*以前的CURLOPT_COPYPOSTFIELDS不再有效。*/
(void)Curl _ sets tropt(数据集。str[STRING _ COPYPOSTFIELDS],NULL);
数据集。post字段=NULL
数据集。post fieldsize=bigsize
打破;
case CURLOPT _ POSTFIELDSIZE _ LARGE:
数据交换数据的大小防止网络库对斯特伦()做
*搞清楚。启用二进制发布。
bigsize=va_arg(param,curl _ off _ t);
如果(数据集。post fieldsize bigsize
数据集。post字段==数据集。str[STRING _ copy post字段]){
/*以前的CURLOPT_COPYPOSTFIELDS不再有效。*/
(void)Curl _ sets tropt(数据集。str[STRING _ COPYPOSTFIELDS],NULL);
数据集。post字段=NULL
数据集。post fieldsize=bigsize
打破;
case CURLOPT_HTTPPOST:
*设置让我们做提供直接提交
data- set.httppost=va_arg(param,struct curl _ http post *);
数据集。http req=http req _ POST _ FORM
数据集。opt _ no _ body=FALSE/*这是隐含的*/
打破;
案例CURLOPT_REFERER:
*要在HTTP推荐人:字段中设置的字符串。
if(data- change.referer_alloc) {
免费(数据-变化。referer);
数据-更改。referer _ alloc=FALSE
result=Curl _ sets tropt(数据集。str[字符串集合引用者],
va_arg(param,char *);
数据-更改。REFERER=数据集。str[STRING _ SET _ REFERER];
打破;
/**中间省略10000行情况情况,但都是想数据数据修正值*/
默认值:
/*未知标签和它的同伴,直接忽略:*/
result=CURLE _ FAILED _ INIT/*纠正这个*/
打破;
返回结果;
}3.真正发送请求:
CURL代码CURL _ easy _ perform(CURL * easy)
CURLM * multi
CURLMcode代码
CURLcode code=CURLE _ OK
int仍在运行
结构时间值超时;
内部rc
CURLMsg * msg
fd _ set fdread
fd _ set fdwrite
FD _ set FD excel EP
int maxfd
如果(!容易)
返回CURLE _ BAD _ FUNCTION _自变量
multi=curl _ multi _ init();
如果(!多)
返回内存不足
mcode=curl _ multi _ add _ handle(multi,easy);
if(mcode) {
curl_multi_cleanup(多);
if(mcode==CURLM_OUT_OF_MEMORY)
返回内存不足
其他
返回卷曲_失败_初始化
/*我们通过立即调用完成来开始一些操作*/
做{
while(CURLM _ CALL _ MULTI _ PERFORM==
curl_multi_perform(多,还在_运行));
如果(!还在运行)
打破;
FD _ ZERO(FD读取);
FD _ ZERO(FD写);
FD _ ZERO(FD excel EP);
/*每秒超时一次*/
暂停。TV _ sec=1;
暂停。TV _ usec=0;
/*旧的不推荐使用的样式:从传输中获取文件描述符*/
curl_multi_fdset(multi,fdread,fdwrite,fdexcep,maxfd);
rc=Curl_select(maxfd 1,fdread,fdwrite,FD exp,time out);
/*方法是提取套接字并等待它们,而不使用
选择。这个完整的替代版本可能应该使用
curl _ multi _套接字()方法。*/
如果(rc==-1)
/*选择错误*/
打破;
/*超时或数据发送/接收=循环!*/
}而(还在_跑);
msg=curl_multi_info_read(multi,RC);
如果(消息)
代码=消息-数据。结果;
mcode=curl _ multi _ remove _ handle(multi,easy);
/*失败了怎么办?*/
mcode=curl _ multi _ clean up(multi);
/*失败了怎么办?*/
返回代码;
}4.从内存去除申请的空间:
void CURL _ easy _ clean up(卷曲*卷曲)
struct会话句柄* data=(struct会话句柄*)curl;
如果(!数据)
返回;
卷曲_关闭(数据);
}php:
1.使用的数据结构:
数据类型说明结构{
结构_ php _ curl _ error错误
struct _ php _ curl _ free * to _ free
结构PHP curl send headers头;
void * * * thread _ ctx
卷曲* cp/* php主要申请这个结构体,但这个结构体包含了C的卷曲这个类型的结构体,所以可以采用ch- cp来设置这个结构体内容*/
php _ curl _ handlers *处理程序;
长id;
无符号整数使用;
zend _ bool输入_回调
zval *克隆;
} php _ curl2。使用的方法:
PHP _函数(卷曲_初始化)
php _ curl * ch
卷曲* cp
zval *克隆;
char * url=NULL
int URL _ len=0;
char * cainfo
if(ZEND _ parse _ parameters(ZEND _ NUM _ ARGS()TSR mls _ CC, s ,url,url_len)==FAILURE) {
返回;
CP=curl _ easy _ init();
如果(!cp) {
php_error_docref(NULL TSRMLS_CC,E_WARNING,无法初始化新的卷曲句柄);
返回_假
alloc _ curl _ handle(ch);
TSR mls _ SET _ CTX(ch-thread _ CTX);
ch-CP=CP;
ch-handlers-write-method=PHP _ CURL _ STDOUT;
ch-handlers-write-type=PHP _ CURL _ ASCII;
ch-handlers-read-method=PHP _ CURL _ DIRECT;
ch-handlers-write _ header-method=PHP _ CURL _ IGNORE;
ch-uses=0;
MAKE_STD_ZVAL(克隆);
ch-克隆=克隆;
curl_easy_setopt(ch- cp,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(ch- cp,CURLOPT_VERBOSE,0);
curl_easy_setopt(ch- cp,CURLOPT_ERRORBUFFER,ch-err。str);
curl_easy_setopt(ch- cp,CURLOPT_WRITEFUNCTION,curl _ write);
curl_easy_setopt(ch- cp,CURLOPT_FILE,(void *)ch);
curl_easy_setopt(ch- cp,CURLOPT_READFUNCTION,curl _ read);
curl_easy_setopt(ch- cp,CURLOPT_INFILE,(void *)ch);
curl_easy_setopt(ch- cp,CURLOPT_HEADERFUNCTION,curl _ write _ header);
curl_easy_setopt(ch- cp,CURLOPT_WRITEHEADER,(void *)ch);
curl_easy_setopt(ch- cp,CURLOPT_DNS_USE_GLOBAL_CACHE,1);
curl_easy_setopt(ch- cp,CURLOPT_DNS_CACHE_TIMEOUT,120);
curl_easy_setopt(ch- cp,CURLOPT_MAXREDIRS,20);/*防止无限重定向*/
cainfo=INI _ STR( curl。cainfo’);
if (cainfo strlen(cainfo) 0) {
curl_easy_setopt(ch- cp,CURLOPT_CAINFO,CAINFO);
#如果已定义(ZTS)
curl_easy_setopt(ch- cp,CURLOPT_NOSIGNAL,1);
#endif
如果(url) {
如果(!php_curl_option_url(ch,url,url_len)) {
_ PHP _ curl _ close _ ex(ch TSR mls _ CC);
返回_假
ZEND _ REGISTER _ RESOURCE(return _ value,ch,le _ curl);
ch- id=Z_LVAL_P(返回值);
}执行真实下载
服务器端编程语言(Professional Hypertext Preprocessor的缩写)函数(curl exec)
CURLcode错误;
zval * zid
php _ curl * ch
if(ZEND _ parse _ parameters(ZEND _ NUM _ ARGS()TSR mls _ CC, r ,zid)==失败){
返回;
ZEND_FETCH_RESOURCE(ch,php_curl *,zid,-1,le_curl_name,le _ curl);
_php_curl_verify_handlers(ch,1 TSR mls _ CC);
_ PHP _ curl _ clean up _ handle(ch);
error=curl_easy_perform(ch-
SAVE_CURL_ERROR(ch,ERROR);
/*头请求返回CURLE _ PARTIAL _ FILE */
如果(错误!=CURLE_OK错误!=CURLE_PARTIAL_FILE) {
if(ch-handlers-write-buf。len 0){
smart _ str _ free(ch-handlers-write-buf);
返回_假
if (ch- handlers- std_err) {
php _ stream *流
stream=(PHP _ stream *)Zend _ fetch _ resource(ch-handlers-STD _ err TSR mls _ CC,-1,NULL,NULL,2,php_file_le_stream(),PHP _ file _ le _ p stream());
如果(流){
php_stream_flush(流);
if(ch-handlers-write-method==PHP _ CURL _ RETURN ch-handlers-write-buf。len 0){
smart _ str _ 0(ch-handlers-write-buf);
RETURN _ STRINGL(ch-handlers-write-buf。c,ch- handlers- write- buf.len,1);
/*刷新文件句柄,以便将所有剩余数据同步到磁盘*/
if(ch-handlers-write-method==PHP _ CURL _ FILE ch-handlers-write-FP){
fflush(ch- handlers- write-
if(ch-handlers-write _ header-method==PHP _ CURL _ FILE ch-handlers-write _ header-FP){
fflush(ch-handlers-write _ header-
if(ch-handlers-write-method==PHP _ CURL _ RETURN){
RETURN _ EMPTY _ STRING();
}否则{
返回真
}关闭程序,清空内存
PHP _函数(curl_close)
zval * zid
php _ curl * ch
if(ZEND _ parse _ parameters(ZEND _ NUM _ ARGS()TSR mls _ CC, r ,zid)==失败){
返回;
ZEND_FETCH_RESOURCE(ch,php_curl *,zid,-1,le_curl_name,le _ curl);
if (ch- in_callback) {
php_error_docref(NULL TSRMLS_CC,E_WARNING,试图从回调中关闭卷曲句柄);
浸水使柔软
urn;
if (ch- uses) {
ch- uses--;
} else {
zend_list_delete(Z_LVAL_P(zid));
}python的pycurl
1.使用的数据结构:
typedef struct {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
CURL *handle; /*引用C的curl的数据结构*/
PyThreadState *state;
CurlMultiObject *multi_stack;
CurlShareObject *share;
struct curl_httppost *httppost;
struct curl_slist *httpheader;
struct curl_slist *http200aliases;
struct curl_slist *quote;
struct curl_slist *postquote;
struct curl_slist *prequote;
/* callbacks */
PyObject *w_cb;
PyObject *h_cb;
PyObject *r_cb;
PyObject *pro_cb;
PyObject *debug_cb;
PyObject *ioctl_cb;
PyObject *opensocket_cb;
/* file objects */
PyObject *readdata_fp;
PyObject *writedata_fp;
PyObject *writeheader_fp;
/* misc */
void *options[OPTIONS_SIZE]; /* for OBJECTPOINT options */
char error[CURL_ERROR_SIZE+1];
} CurlObject;
方法:
1.初始化对象:
static CurlObject *
do_curl_new(PyObject *dummy)
CurlObject *self = NULL;
int res;
char *s = NULL;
UNUSED(dummy);
/* Allocate python curl object */
self = util_curl_new();
if (self == NULL)
return NULL;
/* Initialize curl handle */
self- handle = curl_easy_init();
if (self- handle == NULL)
goto error;
/* Set curl error buffer and zero it */
res = curl_easy_setopt(self- handle, CURLOPT_ERRORBUFFER, self- error);
if (res != CURLE_OK)
goto error;
memset(self- error, 0, sizeof(self- error));
/* Set backreference */
res = curl_easy_setopt(self- handle, CURLOPT_PRIVATE, (char *) self);
if (res != CURLE_OK)
goto error;
/* Enable NOPROGRESS by default, i.e. no progress output */
res = curl_easy_setopt(self- handle, CURLOPT_NOPROGRESS, (long)1);
if (res != CURLE_OK)
goto error;
/* Disable VERBOSE by default, i.e. no verbose output */
res = curl_easy_setopt(self- handle, CURLOPT_VERBOSE, (long)0);
if (res != CURLE_OK)
goto error;
/* Set FTP_ACCOUNT to NULL by default */
res = curl_easy_setopt(self- handle, CURLOPT_FTP_ACCOUNT, NULL);
if (res != CURLE_OK)
goto error;
/* Set default USERAGENT */
s = (char *) malloc(7 + strlen(LIBCURL_VERSION) + 1);
if (s == NULL)
goto error;
strcpy(s, "PycURL/"); strcpy(s+7, LIBCURL_VERSION);
res = curl_easy_setopt(self- handle, CURLOPT_USERAGENT, (char *) s); /*主要在这里调用c的curl的curl_easy_setopt方法,生成一个CURLsessionhandler结构体*/
if (res != CURLE_OK) {
free(s);
goto error;
self- options[ OPT_INDEX(CURLOPT_USERAGENT) ] = s; s = NULL;
/* Success - return new object */
return self;
error:
Py_DECREF(self); /* this also closes self- handle */
PyErr_SetString(ErrorObject, "initializing curl failed");
return NULL;
}2.设置参数
do_curl_setopt(CurlObject *self, PyObject *args)
int option;
PyObject *obj;
int res;
if (!PyArg_ParseTuple(args, "iO:setopt", option, obj))
return NULL;
if (check_curl_state(self, 1 2, "setopt") != 0)
return NULL;
/* early checks of option value */
if (option = 0)
goto error;
if (option = (int)CURLOPTTYPE_OFF_T + OPTIONS_SIZE)
goto error;
if (option % 10000 = OPTIONS_SIZE)
goto error;
#if 0 /* XXX - should we ??? */
/* Handle the case of None */
if (obj == Py_None) {
return util_curl_unsetopt(self, option);
#endif
/* Handle the case of string arguments */
if (PyString_Check(obj)) {
char *str = NULL;
Py_ssize_t len = -1;
char *buf;
int opt_index;
/* Check that the option specified a string as well as the input */
switch (option) {
case CURLOPT_CAINFO:
/*此处省略10000行,为pycurl未实现的curl的功能*/
case CURLOPT_CRLFILE:
case CURLOPT_ISSUERCERT:
/* FIXME: check if more of these options allow binary data */
str = PyString_AsString_NoNUL(obj);
if (str == NULL)
return NULL;
break;
case CURLOPT_POSTFIELDS:
if (PyString_AsStringAndSize(obj, str, len) != 0)
return NULL;
/* automatically set POSTFIELDSIZE */
if (len = INT_MAX) {
res = curl_easy_setopt(self- handle, CURLOPT_POSTFIELDSIZE, (long)len); /*可以看到pycurl的设置参数也就是使用的c的curl的curl_easy_setopt,即是对C的curl的一种封装*/
} else {
res = curl_easy_setopt(self- handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
break;
default:
PyErr_SetString(PyExc_TypeError, "strings are not supported for this option");
return NULL;
/* Allocate memory to hold the string */
assert(str != NULL);
if (len = 0)
buf = strdup(str);
else {
buf = (char *) malloc(len);
if (buf) memcpy(buf, str, len);
if (buf == NULL)
return PyErr_NoMemory();
/* Call setopt */
res = curl_easy_setopt(self- handle, (CURLoption)option, buf);
/* Check for errors */
if (res != CURLE_OK) {
free(buf);
CURLERROR_RETVAL();
/* Save allocated option buffer */
opt_index = OPT_INDEX(option);
if (self- options[opt_index] != NULL) {
free(self- options[opt_index]);
self- options[opt_index] = NULL;
self- options[opt_index] = buf;
Py_INCREF(Py_None);
return Py_None;
}
3.关闭连接,或者说是删除内存中对象。
static PyObject *
do_curl_close(CurlObject *self)
if (check_curl_state(self, 2, "close") != 0) {
return NULL;
util_curl_close(self); /*删除了CurlObject对象*/
Py_INCREF(Py_None);
return Py_None;
}由以上分析可以看出,php的curl和python的curl都是对curl的一种封装,如果想写出一个更符合自己需求的配置型爬虫,可以考虑直接用C写,不过C的爬虫是不适合快速开发,这由代码量决定。
当然更好的建议是使用webkit做爬虫,作为部分浏览器内核,毋庸置疑。以后再说.
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。