python实现curl,php_curl

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: