这里以PHP版为例,尽量说得通俗点吧,水平实在有限,见谅。虽然并没有多高深,但请转载者注意起码的礼貌。
目前我这里所有的获取全文输出的网站大概是三种情况:
- 要输出的内容集中在一页上,也就是看似列表页的页面里集中了你想要的所有内容,并不需要点击“更多”或“继续阅读”才能看到文章整体。比如糗事百科、wiki。
- 有列表页,要查看相应文章必须点击链接进入。
- json方式写入。特征就是查看源文件并不能找到你在浏览器中看到的内容。比如腾讯新闻图片(链接),它的真正内容在这(链接)。
第一种最省事,第二种最常见,第三种稍麻烦。
今天先讲第二种。
以知乎日报为例 (链接),先看代码:(把下列源码存为zhihu.php)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php include "gethtml.php"; $regex_link = '/(?<=<a href="\/story\/).+?(?=")/'; $regex_tit = '/(?<=<title>)(.+?)(?= -)/s'; $regex_con = '/<span class="img-source">.*?(?=<div class="qr">)/s'; $header = '<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>知乎日报</title>'; $footer = '</channel></rss>'; $html = gethtml('http://daily.zhihu.com/'); if (preg_match_all($regex_link, $html, $links)) { foreach($links[0] as $link) { $link = preg_replace('/(.+)/','https://daily.zhihu.com/story/$1', $link); $content = gethtml($link); preg_match($regex_con, $content, $article); preg_match($regex_tit, $content, $title); $rss.= '<item><title>'.$title[0].'</title><link><![CDATA['.$link. ']]></link><description><![CDATA['.$article[0].']]></description></item>'; } file_put_contents('zhihu.xml',$header.$rss.$footer); } ?> |
重点是第8行往后。只解释我认为重要的,不明白的可以讨论。
第2行,引入gethtml方法,来自下面的代码。
看一下第8行gethtml(‘https://daily.zhihu.com/’)得到了什么(链接),虽然有点乱,但是目的达到了,https://daily.zhihu.com/ 我已经抓到本地服务器上。
第9行是要挑出需要的链接 $links(链接)
第13行利用这些链接继续抓取页面 $content=gethtml($link)
第14、15行从$content里查找需要的$title(文章标题)和$article(文章内容)
后面就是按RSS要求的格式输出,并最终生成xml文件。
最后,想办法打开https://feedx.net/rss/tutorial/zhihuu.php,只要程序不出错,就会同目录生成zhihu.xml,订阅地址即为https://feedx.net/rss/tutorial/zhihu.xml
怎么自动打开那个网址呢,crontab、计划任务、cPanel、wordpress插件都可以,如果都没有的话,网上也是有人提供这个服务的,https://cron-job.org,自己去看吧…
上面我说的查找、挑出都是用正则来实现的,此外最好对html特别熟悉,操作起来才能得心应手。
想要自己完成还是要有一定基础的,完全靠伸手是不现实的,还不如去买那些能可视化操作的产品。如果正则不熟或不想学,可以试试PHP Simple HTML DOM Parser,类似jQuery。
============================================
参数的用法:
默认可以不加参数,基本写法是这样的:
1 2 3 4 |
$headers=['User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36','Cookie: BAIDUID=4C2D58EAE60F2ACDB32DCAAAA9795A4D:FG=1;H_WISE_SIDS=106370_122302; BDSVRTM=13']; $args=['headers'=>$headers,'header'=>1]; $url='https://feedx.net'; $html=gethtml($url,$args); |
上面的意思是我去抓取的时候让自己更像个浏览器,模拟的是chrome 65.0.3325.162版,还加上了cookie;因为一个网址可能会跳转很多次才到目标网址,通常我们是不用去管这些的,比如我好奇心很重,就可以把header信息也打印出来。还有更多的一些用法可以参考curl自己添加。
============================================
下面是在别人的基础上自己总结的利用curl抓取页面的方法,把下面源码存为gethtml.php,与zhihu.php放于同一目录下。我所有的抓取都是用的这个方法,当然,省事的话可以用 file_get_contents,那就是真正的20行代码完成全文RSS输出了,不过可选的参数就没有了,有的页面会抓取不到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php function gethtml($url,$args=null){ $proxy = $args["proxy"]?$args["proxy"]:''; $headers = $args["headers"]?$args["headers"]:['User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36']; $nobody = $args["nobody"]?$args["nobody"]:0; $header = $args["header"]?$args["header"]:0; $ch = curl_init(); $options = array( CURLOPT_URL => @$url, CURLOPT_PROXY => @$proxy, CURLOPT_HTTPHEADER => @$headers, CURLOPT_NOSIGNAL => 1, CURLOPT_HEADER => @$header, CURLOPT_NOBODY => @$nobody, CURLOPT_RETURNTRANSFER => 1, CURLOPT_FOLLOWLOCATION => 1 ); if (preg_match('/^https/',$url)){ $options[CURLOPT_SSL_VERIFYHOST] = 2; $options[CURLOPT_SSL_VERIFYPEER] = 0; } curl_setopt_array($ch, $options); $data = curl_exec($ch); $curl_errno = curl_errno($ch); curl_close($ch); if($curl_errno>0){ return 'error'; }else{ return $data; } } ?> |
太好了,先謝謝了。慢慢看完再請教你。
大概看完了,再次謝謝站長的分享。
簡單來說就是對多層頁面使用函數gethtml獲得主網頁及下級網頁內容後,使用正則分析生成輸出的xml文件。 對不同網站有可能需要通過修改正則來處理不同頁面內容。看完後我在自己的apache上试验通过,下一步是试试不同的网站。自己雖然是多年程序員,但都是数据库、cs架构的,從來沒接觸過web這部分。下面的问题还请站长解答:
1. 如何自动执行php?是使用crontab吗?还是通过一个主php?
2. 访问权限的问题,php不能让所有人访问,生成的xml的访问权限也因应不同进行设置,这部分如何解决?
再次感谢!
1. 我用的是空间商后台管理面板cPanel里模拟crontab的一个可视化排程工具,cron jobs(https://confluence2.cpanel.net/display/ALD/Cron+Jobs)。确实也可以通过PHP自己来完成(搜索:PHP 排程,有很多结果。我没试过,总觉得不保险)
2.没太看懂。我只是把PHP起了个别人想不到的名字,或者你也可以把xml生成到其它目录。这样好像并不涉及权限问题。
谢谢,我研究研究。
下面是我学写的蓝影网的php。测试运行通过了,阅读器里能使用。但有两个问题,能帮我看看吗?自己试了很多次都解决不了。
1. 在获得内容时,总是不能把 tag 去掉。
2. 不知道为什么在阅读器中总是不能显示下载链接。
再次感谢!
<?php
include "gethtml.php";
$regex_link = '/(?<=<h2 class=\"entry-title\"><a href=").+?(?=")/s';
$regex_tit = '/(?<=<title>)(.+?)(?=<\/title>)/s';
$regex_con = '/(<article.*?>)(.*?)(<\/article>)/s';
$header='<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>蓝影网</title>';
$footer='</channel></rss>';
$html=gethtml('https://www.lanyingwang.com/');
if(preg_match_all($regex_link, $html, $links)){
$size=count($links[0]);
for($i=0;$i<$size;$i++){
$link=$links[0][$i];
$content=gethtml($link);
preg_match($regex_con,$content,$article);
preg_match($regex_tit,$content,$title);
$rss.='<item><title>'.$title[0].'</title><link><![CDATA['.$link.']]></link><description><![CDATA['.$article[0].']]></des$
}
file_put_contents('lanyingwang.xml',$header.$rss.$footer);
}
?>
已回复邮箱。贴在这里可能帮助到别人
按你的要求,需要明白这两个用法(零宽断言):
(?=exp) 匹配exp前面的位置不包括exp本身
(?<=exp) 匹配exp后面的位置不包括exp本身
/(exp)(.*?)(exp)/
只是进行了分组,它是包括exp本身的。所以消不掉。(当然,你已经把它分组了,也可以用一个替换得到想要的内容)
但是这个又不能这么写
/(?<=<article.*?>)(.*?)(?=<\/article>)/
因为零宽断言不能含有通配符
可以这样匹配:
/<header class=”entry-header”>.*?(?=<\/article>)/
也就是紧贴着article标签的header开始(包括header)到</article>为止(不包括</article>)
其实也不必为这些标签烦恼。我试过,标签不配对问题都不太大。多一个少一个的不用纠结。
最近再弄澎湃网https://www.thepaper.cn/的全文输出,似乎有点问题,烦请博主有空做个全文RSS造福大家。
没问题,尽快。
你好,能做一个懂球帝头条的全文输出码?https://www.dongqiudi.com/?tab=1
可以,你一般什么时间段看,一天更新最多1次
一般晚上7点后吧,谢谢了!
顺便能不能把珍藏的某知音全文地址也一并发给我呀
最近發現用Simple HTML DOM Parser(https://simplehtmldom.sourceforge.net/)比正則來得簡單好用,站長可以試試。
PS: 站長能否教下如何弄微博的RSS輸出,微博需要登錄,自己試了些教程,總是有問題,先謝謝了。
这个用过,总觉得不如正则来得直接,弃用了。
我对微博没啥兴趣,刚看了看,确实页面是抓不到的,要模拟登录什么的,curl可以办到吧,这里不讨论这个。
如果只是想要抓到页面,其实有别的办法。教程随后更新。
楼主太厉害了!!!能不能帮做个冷笑话的 rss
网址https://lengxiaohua.com/
非常感谢,终于可以比较方便的自己做rss源了,期待后面教程的更新。
客气,抛砖引玉。
完全自己琢磨的,不知道正经应该怎么做。
感谢楼主分享,感觉还是有点难度。。。直接用你的吧嘿嘿
先说一声谢!
一直喜欢rss阅读方式!很高兴遇见你!呵呵
嗯,我也一样,所以才有了这网站
我有一个国外的服务器,新建一个站点,然后我将你这上面的两个文件放在里面。初步能得到XML的文件。现在咨询一下,如何能让这两个文件自动更新。能读到最新的文件呢。设置自动刷新吗?我是VPS。再就是关于这个墙的问题,在国外存到服务器上是不经过墙的所以这个没问题。我们这边的电脑通过RSS订阅软件拉取数据时。拉过来的是XML格式的国内外的文档。这个墙是如何辨别的?HTTPS能保护服务器和域名吗?我是担心我服务器IP别被封了。感谢有空答复。谢谢。
只需要将space.php自动执行就可以,你是vps,那有很多办法执行它。排程、计划任务之类的。
自己用不必考虑墙的问题。
还有一个咨询问题,有些国外网站上面的图片在国内是看不到的,我看你 个站点上说存到你的服务器上面,复杂不。我服务性能高些,我想试试能不能放我服务器上。看看效果。谢谢
图片本地化也是写在space.php里,每个网站不同,具体写法也有些不同。大概流程是取得xml文件里的图片地址,把图片存到本地服务器,替换xml里的图片地址。
这样一个网站:
原网址:https://www.qhrb.com.cn/organ/organsee/ 我做下令规则space.php如下:<?php
include "gethtml.php";
$regex_link = '/(?<=<a href=").+?(?=")/s';
$regex_tit = '/(?<=)(.+?)(?=)/s’;
$regex_con = ‘/.*?(?=)/s’;
$header=’期货日报’;
$footer=”;
$html=gethtml(‘https://www.qhrb.com.cn/organ/organsee/’);
if(preg_match_all($regex_link, $html, $links)){
$size=count($links[0]);
for($i=0;$i<$size;$i++){
$link=preg_replace('.+','$1',$links[0][$i]);
$content=gethtml($link);
preg_match($regex_con,$content,$article);
preg_match($regex_tit,$content,$title);
$rss.='’.$title[0].”;
}
file_put_contents(‘qhrb.xml’,$header.$rss.$footer);
}
?>
不知道问题出在哪里,麻烦指点一下,万分感谢!
这个错误太多了。
弄这个要对三个东西有所熟悉,html、正则表达式和php,虽然是用php写的,其实前两个更重要一些。
对教程里的每一步都要清楚在干什么,其实,不用php环境也可以知道这步做得对不对,比如我要抓取一篇文章,先打开那篇文章,查看源文件,复制到一些稍高级的编辑器里(支持正则查找,比如notepad++),查找,查找模式选择正则和匹配新行。只要能查到的是你想要的那块代码,这就成功了,这就是$regex_con的作用。那块代码就是html的知识,查找的内容就是正则表达式。
以此类推,$regex_tit是需要能查什么也就清楚了。
链接,标题,内容分别是这样的正规则:
$regex_link = ‘/(?<=<a href=").+?(?=")/s';
$regex_tit = '/(?<=)(.+?)(?=)/s’;
$regex_con = ‘/.*?(?=)/s’;
在NOTEPAD++里面我能定位到他们。
就是后面的那个:
$html=gethtml(‘https://www.qhrb.com.cn/organ/organsee/’);
if(preg_match_all($regex_link, $html, $links)){
$size=count($links[0]);
for($i=0;$i<$size;$i++){
$link=$links[0][$i];
$content=gethtml($link);
preg_match($regex_con,$content,$article);
preg_match($regex_tit,$content,$title);
$rss.='’.$title[0].'<![CDATA['.$article[0].']]
链接不知道如何弄出来,您上面的是相对地址,这个是绝对地址。我测试了几个方法也找不出。再次感谢。
我发现问题了,您这个网站把我一些代码过滤掉了。我把我写的源码放这里:https://qhlt.cn/thread-4791-1-1.html 麻烦您帮我看看是哪里的问题,十分感谢。
问题不太大,稍改下就可以了。
php的正则规则的格式是这样的’/这里是规则/’,所以,规则里是不能出现“/”的,如果有需要转一下,改为“\/”。或者把正则格式改为’#这里是规则#’,这样就可以直接用“/”了。
有三处错误
1. 取得链接那个规则错了,有”/”;
2. 标题的正则也错了,同上;
3. $link=preg_replace(‘.+’,’$1′,$links[0][$i]);确实是有问题的,其实这个不用替换,直接用$link=$links[0][$i];之所以有时需要替换是因为得到的链接是不带它本身的域名的,比如得到的链接是这样的$link=’/contactus/index6.html’;这样要抓取的话gethtml($link)是得不到内容的,此时需要把$link加上域名,$link=preg_replace(‘/(.+)/’,’https://xxx.com/$1′,$link);
万分感谢,搞定了。现在还有一个小技术问题,就是如何让这个space.php的文件定时运行一下,好查有没有新的资讯更新。我看你在有些文章中说用CURL类的,具体怎么个弄法?
不知道你的具体运行环境,如果是在你的vps里,那你查查cron job的用法。
发现了个更省事的办法,真没想到这现成的大白馒头就放在嘴边了。
https://cron-job.org/
今天下午费了老长的时间弄这个批量执行计划,我是WIN 的VPS 弄了好半天也没有成功,希望这个网站不要有什么限制。
我试过了,可用,好用。
直接把网址放上,定好时间,定时执行。最短间隔可每分钟都执行。
我晚上也做了几个放上面了,有些能执行,有些执行错误,我看说明是超时,我想是否可以在提取数据时设一限制。比方说一次只取最新的20个。一次执行时提取的数据少一些。是不是就不会出现这种超时的问题了。
如果代码确定没问题,限制在这
$size=count($links[0]);
可以直接改成你需要的数字。
$size=20;
今天做新浪网的RSS时出现了一点问题,这个是我问题的链接:https://qhlt.cn/thread-4791-1-1.html 您的网站过滤源码,所以我就发到我论坛上面了。有空麻烦您看一下,看看有没有处理方法。 就是链接提取时出现了一些不想要的链接。十分感谢。
通常是这么解决的,再精确定位一下,你已经取得了本页的$html,preg_match($regex_ul,$html,$ul);这样就能得到$ul[0];这时要改preg_match_all($regex_link, $html, $links为preg_match_all($regex_link, $ul[0], $links。大概结构是这样的:
$html=gethtml(‘https://www.nationalgeographic.com.cn/science/space/’);
preg_match($regex_ul,$html,$ul);//把需要的代码块再做一次筛选匹配
if(preg_match_all($regex_link, $ul[0], $links)){
//其它代码
}
只需要你自己写出$regex_ul的正则,应该没问题吧。
————————-另一种————————-
当然,不止一种解决办地,具体到这个,仔细观察,你需要的链接都是https://finance.sina.com.cn/开头的,这样其实是可以排除那些干扰链接的
$regex_link = ‘#(?<=<li><a href="https://finance.sina.com.cn/).+?(?=")#s';//用域名做限定,排除干扰项
……
$link=’https://finance.sina.com.cn/’.$links[0][$i];//再把域名加回来
十分感谢,新浪的至少能提取出新闻了。现在我就考虑有没有好的项目呢,这个RSS资讯自己或小满园看还行,一多就容易出现侵权的问题,同时墙的问题也一直存在。我是做投资的。设想是做一个类似的新闻信息聚合,看看有没有市场。现在先自己弄着玩吧。感谢这几天的指导,我也弄了一个小站,已经加你友情链接,有空多交流:)
做这个的人好少啊。最近遇到一个问题,咨询一下,我抓的经常出现只有标题没有内容,或连标题也没有,当然内容也没有了。我用的是quiterss订阅,双击能看到原网址确实有内容,同时通过正规则我发现并没有什么问题。我用的是https://cron-job.org 这个定期刷新的。您经验多,有没有解决方法,十分感谢。
本来想研究一下的,然而完全看不懂~
这是我做的一个论坛的RSS输出。现在的问题是一对一对的输出,在列表截链接时出现了一点问题,麻烦有空帮我看看能解决不。 https://qhlt.cn/thread-6447-1-1.html 这个是问题的详细,这里回复会过滤一些源码,所以我放到一个贴子里面了。这个论坛是用DISCUZ 7.2做的。
#(?<=href=").+?(?=" title="新窗口打开" target="_blank")#
注意,最后没有S
这个是我做的RSS的地址:https://rssft.com/qhlt/index.xml
十分感谢楼主分享教程,我在vultr新建了个网站,php版本5.2,上传了这两个文件,运行没有反应哪?也不能生成xml文件。能是什么原因哪?
可能网站改版之类的原因,中间多加几个echo 调试一下,看看到底哪步出问题了。
我目前也是用的vultr。
这个例子自从放上去就再没测试过,这两天有事,过一两天再调一下,让它能运行。
也可能今晚就完成,别太期待
会是Nginx的原因不?哈哈,还是期待啊,不急不急。就是想做源自己用,另外我还用Miniflux做了个订阅站,利用fever api,在reeder里看,挺不错的。
已经更新,程序可以跑通了。
晕啊,php7.1 这个函数gethtml($url,$json)好像要把两个参数填全才行,像这样gethtml(‘https://daily.zhihu.com/’)不行。。。手贱,安了7.1。
没事,那就随便加个参数gethtml(‘https://daily.zhihu.com/’,'{“host”:”daily.zhihu.com”}’);
還是不行,出錯。畢竟我基本對php一點也不懂。。
可以试试第三方的自动RSS全文输出网站。https://feedocean.com,它的全文输出基于goreadly项目:https://github.com/antchfx/goreadly
感谢分享,收藏了!:”)
这几天我做金融街的RSS出现了些问题,麻烦帮我看一下我错在哪里了:https://www.qhlt.cn/thread-12656-1-1.html 按之前的注意事项检查了好多遍也没有看出问题所在。因为你这个网站过滤一些代码。所以我贴到一个论坛上面了。方便时加我一下QQ:95527664
刚才发给你回复了,不知道收到没有。
刚才想咨询一下我做的这个RSS出现了些问题。想给你发个地址,帮着看一下,发现你这里不能贴地址了。我怎么加你呢。要不您加我QQ:95527664 或您向我邮箱发一下您的微信,刚才我给您转了9块。那个微信不是我的,不过也可以联系到我。
是可以贴地址的,超过两个或因为一些其它规则才会去垃圾箱,我是能看到的。我会抽空看一下。
另外,小事一桩,无需付费……
你用的是不是海外服务器,好像它给禁了,我用了代理是可以抓到的,去掉代理就不成,会超时,基本抓不到东西,不过好解决,它的手机端是没禁用墙外浏览的。
对比一下PC端的链接和手机端的链接:
https://futures.jrj.com.cn/2018/04/16112124394219.shtml
https://m.jrj.com.cn/madapter/futures/2018/04/16112124394219.shtml
要把得到$link稍做修改:
$link=preg_replace(‘#https://futures.jrj.com.cn(.+)#’,’https://m.jrj.com.cn/madapter/futures$1′,$link);
所以后面的抓取是要依据https://m.jrj.com.cn/madapter/futures/2018/04/16112124394219.shtml来进行,相信到这儿应该明白了吧。
还有个好处就是页面更轻盈了,抓取负担会小很多,所以基本上只要有手机端页面的我肯定会去抓手机端的。
好的,谢谢,我弄一下,我是海外的服务器,呵呵
有没有班办法抓取微信公众号文章
试过,抓不到,本地可以,放服务器上就不行了。