代码仔的实验室_微信公众平台 & PHP抓取网页

前言

用了一早上的时间,成功实现了PHP抓取csdn博客信息,并且通过公众平台实现了自动回复。

实现效果:用户在我的公众平台上输入“博客”,自动返回实时的博客访问量等信息,

这里边有两个重要的部分,一个是微信公众平台的信息获取、解析并按照格式返回内容;另一个是在后台利用SAE提供的类实现网页抓取并筛选出所需的部分。

欢迎大家关注我的公众号“代码仔的实验室”



微信公众平台

新手接入

在申请好了公众号之后,如果需要打开开发模式,需要进行接口验证,这部分的内容微信的开发文档里都有,并且附上了例子,我们需要做的就是有一个自己的服务器,当微信的服务器发来数据包之后进行处理,返回正确的数据包即可,相关的代码微信都有提供,只要放在服务器目录里,能被调用到就好了。

微信开发文档_新手接入

获取数据包并返回

这部分微信也提供了例子,在wechatCallbackapiTest类中,有一个公有成员函数responseMsg(),相当于一个简单的HelloWorld例子,原始的例子里并没有调用这个函数,我们可以看看这里的代码,这是一个基本的接收消息、解析、自动回复的函数。

我对这个函数加了中文注释,便于大家理解。

public function responseMsg()

    {

		//根据不同的服务器环境,这里需要获取POST来的数据

		$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];



      	//解析数据

		if (!empty($postStr)){

                //按照XML文件的格式解析

              	$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

                $fromUsername = $postObj->FromUserName;

                $toUsername = $postObj->ToUserName;

                $keyword = trim($postObj->Content);//trim函数负责去除前后的空格

                $time = time();

                $textTpl = "<xml>

							<ToUserName><![CDATA[%s]]></ToUserName>

							<FromUserName><![CDATA[%s]]></FromUserName>

							<CreateTime>%s</CreateTime>

							<MsgType><![CDATA[%s]]></MsgType>

							<Content><![CDATA[%s]]></Content>

							<FuncFlag>0</FuncFlag>

							</xml>";//制作返回数据包XML文件

				if(!empty( $keyword ))

                {

              		$msgType = "text";//返回的数据类型,这里是text文本信息

                	$contentStr = "Welcome to wechat world!";//返回数据的内容,默认是Welcome to wechat world!

                    //注意这里格式化写入,$fromUsername对应在XML文件里的位置在ToUserName,

                    //因为我们要返回信息,所以接受到的数据包里的"收件人"就成了"发件人"

                	$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);

                	echo $resultStr;//返回数据包

                }else{

                    //如果收到的数据为空,则返回对应信息

                	echo "Input something...";

                }



        }else {

        	echo "";//如果无法获取到POST数据包,则返回对应信息

        	exit;

        }

    }




有了这个代码,我们只需要修改我们需要的自定义部分,就可以顺利的返回数据。注意这里建议将错误信息补全,考虑到尽可能多的错误情况并echo对应的信息,将来查错会非常方便。

官方例子中的这个类不好用,还是我们自己写一个吧,在写之前简单的思考了一下,大概的结构是这样的:

class wechat
{
	public function distribute();//判断收到的信息是哪些
	public function text($postObj);//文本消息
	public function location($postObj)//地理位置消息
}


如果将来需要扩展新的回复内容,可以在distribute函数中增加新的判断项,并添加新的处理函数,就可以有效的应对新的内容。

distribute()是入口函数,负责将收到的信息进行解析,找到其中的MsgType,判断接受到的信息类型,并传递给相应的处理函数,如果无法获取数据返回对应的错误值。

代码如下:

public function distribute()//判断收到的信息是哪些
    {
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
        //extract post data
        if (!empty($postStr))
        {
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); 
            $msgType = $postObj->MsgType;

            switch ($msgType) //分发
            {
                case "text":
                    $this->text($postObj);
                    break;
                case "location": 
                    $this->location($postObj);
                
                default:
                    echo "未知的消息类别";
                    break;
            }
        }
        else//无法得到返回值
        {
            echo "无法得到返回值";
        }

    }



text()是负责处理文本的函数,是这次开发的重点,主体的结构参照了微信官方的例子,在其中进行了自定义,包括对特定信息的自动回复,比如这次实现了当收到“博客”的时候,自动返回博客信息,如果收到了其他信息,返回通用的自动回复信息。

代码如下:

public function text($postObj)//文本消息
    {
        $content = trim($postObj->Content);

        switch ($content)
        {
            case "博客":
                $info = new fetch();
                $result = $info->get();
                $contentStr = "我的博客\n《Coder成长之路》\n目前信息:\n";
                $contentStr .=$result[0]."\n";//访问
                $contentStr .=$result[1]."\n";//积分
                $contentStr .=$result[2]."\n";//排名
                $contentStr .=$result[3]."\n";//原创
                $contentStr .=$result[4]."\n";//转载
                $contentStr .=$result[5]."\n";//译文
                $contentStr .=$result[6]."\n";//评论
                $contentStr .= "欢迎访问我的博客\n http://t.cn/8kvGx7T \n";
                break;
            
            default:
                $contentStr = "欢迎使用我的公众号,目前只有 1 个功能\n其余功能正在开发当中,请谅解。\n1. 回复“博客”可以获得我的博客的实时信息。";
                break;
        }
        $fromUsername = $postObj->FromUserName;
        $toUsername = $postObj->ToUserName;
        $keyword = $content;
        $time = time();
        $textTpl = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[%s]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                        <FuncFlag>0</FuncFlag>
                    </xml>";
        if(!empty( $keyword ))
        {
            $msgType = "text";
            $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
            echo $resultStr;
        }
        else
        {
            echo "无法获取输入的信息";
        }
    }



主要的内容和之前的例子一样,如果有疑问可以看之前有中文注释的代码,如果还是有问题可以在下边评论。


地理位置信息还没有做,目前也还没有什么想法,原本想返回一个当地的地图,但是坑爹的微信公众平台不支持订阅号发送图片,只有服务号可以...坑……

或许可以返回一下周围的餐馆信息..


PHP抓取网页

SAE的类

对于网页抓取,SAE提供了一个类方便我们调用,虽然也支持curl,但是原文是这么说的...大家体会一下……



为了少收费..我还是乖乖用它的类吧。其实都挺简单的,就像这样

$page = new SaeFetchurl();

$content = $page->fetch(“http://blog.csdn.net/yuri_4_vera");


这样就能把整个网页抓下来了,如果这时候echo $content,会看到整个HTML代码以文本的形式输出。

正则表达式

抓到网页很简单..难的是怎么把访问量评论数什么的挑出来..我关注的部分在这里:

<ul id="blog_rank">

    <li>访问:<span>508次</span></li>

    <li>积分:<span>72分</span></li>

    <li>排名:<span>千里之外</span></li>

</ul>

<ul id="blog_statistics">

    <li>原创:<span>7篇</span></li>

    <li>转载:<span>0篇</span></li>

    <li>译文:<span>0篇</span></li>

    <li>评论:<span>0条</span></li>

</ul>


我最初想到的是字符串匹配...实在想不出简单的办法,于是想要利用之前Python写的正则表达式,但好像两个函数支持的不一样,总有些符号不太对,PHP的函数会报错,后来在网上搜索了很多资料,很难找到适合我的需求的,我想要从<ul>标签开始,直到</ul>标签结束,中间的所有标签都不要,只要里边的文本。

最后实在没办法,找了一些例子试了试,用了三个例子,改了改,这样实现了挑选:

1.找到所有匹配<li>标签的元素

2.去除“<span>”(包括</span>里的<span>)

3.去除“/”

代码变得略复杂..用了三次正则表达式,一次搜索两次替换

class fetch

{

    public function get()

    {

        $page = new SaeFetchurl();//SAE的抓取网页类

        $content = $page->fetch("http://blog.csdn.net/yuri_4_vera");

        

        if($page->errno() == 0)

        {

            $regex = ‘/<li>(.*?)<\/li>/si’;//第一次匹配的正则表达式,找出所有<li>和</li>内的部分

            if(preg_match_all($regex, $content,$result,PREG_PATTERN_ORDER))

            {

                for ( $i = 0; $i < 7; $i ++ )//对于每个部分分别进行操作

                {

                        $result[1][$i] = preg_replace("<[][^<span>]*>","", $result[1][$i]);//去除<span>部分

                        $result[1][$i] = preg_replace("<[][^/]*>","", $result[1][$i]);//去除”/”

                }

                return $result[1];

            }

        }

        else

            echo $page->errmsg();

    }

}


反思

正则表达式学不好耽误了很长时间...始终没法有效的挑出需要的片段并剔除不要的部分

这次使用了SVN工具,很方便的上传代码。

订阅号真的坑..只能发文本好吗……谁借我个服务号试试?哪怕一个月只能推送一条…我认了..

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值