详情页
详情
缘起
Chrome 浏览器主页被替换成了域名高仿百度入口, 搜索中间就给我打美女广告. 所以顺手点开了, 好吧这很美女, 我的内心非常平静, 甚至还想写一个爬虫...
于是正正经经的开始写爬虫. 首先需要分析一下网站的 html 结构和 URL 路径规则, 然后通过 PHP 自带的 DOMDocument 对象加载返回的 HTML 字符串获取 DOM 结构, 这就可以快速方便获取栏目分类和图片下载关键属性 src. 例如:
$htmlStr =<<<HTML<div id="main"> <ul> <li > 主页 </li> <li > 栏目 1</li> <li > 栏目 2</li> <li><img src="download/1.jpg"></li> </ul></div>HTML;$dom = new DOMDocument();$dom->loadHTML($htmlStr);$src = $dom->getElementById('main')->getElementsByTagName('li')[3]->getElementsByTagName('img')[0]->getAttribute('src');echo $src;// 输出 download/1.jpg
如果你熟悉原生 JavaScript 的 DOM 解析, 会感觉和 PHP 的 DOMDocument 对象的用法简直一模一样. 我们的目标就是遍历所有目录, 合理解析图片的下载路径, 然后下载保存到本地文件夹. PHP 自带多种下载图片方法, 这里我们用 file_get_contents 和 file_put_contents 两个函数:
$imgUrl ='http://www.v7v.club/bg.jpg';$saveDir ="img/bg.jpg";// 必须有 img 文件夹存在 $img = file_get_contents($imgUrl);file_put_contents($saveDir,$img);
这几行代码就能在下载一张 bg.jpg 图片到本地了.
下面继续分析目标站点
详情页
提取重要的显示元素和 HTML 结构. 一个详情页只有一张需要的图片, 通过页码总数可以知道这系列图共有 8 张.
图片
<div id='bigpic'> <a href='1203_2.html'> <img src="http://www.h3399.cn/uploads/allimg/20170316/201703161758031212.jpg"> </a></div>
图片总数
<div class="pageart" id="657"> <ul> <li><a > 共 8 页: </a></li> <li><a href="1663_7.html"> 上一页 </a></li> <li><a href="1663.html">1</a></li> <li><a href="1663_2.html">2</a></li> ... </ul></div>
注: 此处 id=657 并没有什么暖用, 因为一个页面 id=657 存在十几, 违背了 id 唯一的原则, 属于建站人员滥用 id .
主页
主页分为三部分, 导航, 图片展示窗体, 分页.. 导航主要是获取子栏目路径, 如果手动填写就可以省去解析这一步. 每个栏目有 n 页, 每一页有多个模特, 每个模特进去又有多张图片. 我们提取了 HTML 结构部分的关键代码, 用作获取元素节点参考.
导航菜单
<div id="nav"> <li><a href="/"> 网站首页 </a></li> <li><a href="/qcmn/"><span > 清纯美女 </span></a></li> <li><a href="/xgmn/"><span > 性感美女 </span></a></li> <li>...</li></div>
图片展示窗体
<div id="container"> <div class="post masonry-brick"> <a href="/qcmn/1320.html" title="美少女写真"> <img src="http://xxx.xxx.com/uploads/allimg/20170427/201704270749161.jpg"> </a> <div class="piax"> <h2><a href="/qcmn/1320.html"> 美少女写真 </a></h2> <div class="pac"></div> </div> </div> <div class="post masonry-brick">...</div></div>
分页页码
<div id="pager"> <li > 首页 </li> <li class="thisclass">1</li> <li><a href="list_1_2.html">2</a></li> <li><a href="list_1_3.html">3</a></li> <li> <span class="pageinfo"> 共 <strong>29</strong > 页 <strong>227</strong > 条 </span> </li></div>
执行演示
网站上的图片 src:
<img src="http://www.h3399.cn/uploads/allimg/20170316/201703161758031212.jpg">
注意到这个站存放文件 src 结尾是多余一个空格的, 并且是以 20170316 这样的日期目录分文件夹的, 所以很多图片是混在了一起, 应该是靠数据库表映射图片路径的, 在代码中我们根据页面编号对每个模特重新建立文件夹, 所以很容易和原站对比结果.
做这个比较是要说明, 全站抓取趋近于 100%, 难度会越来越大. 这里的一个原因是网站 HTML 不能被 PHP 解析成 DOMDocument 结构, 可能是异常日文字符的问题, 尝试转码也没能解决, 返回的 dom 是 NULL. 单独用正则表达式提取, 结果是 186(占 98.41%). 好了好了, 到这里就可以, 对个骗流量的美女图站这么较劲让我怎么继续深入. 下面进入 FAQ 自问自答环节.
FAQ
Q: 如果不能用 JavaScript 发起 AJAX 请求写爬虫, 那为什么 PHP 可以, 同样是 HTTP 请求.
A:JavaScript 发起 AJAX 请求有同源跨域限制, 除非服务器端允许跨域, 几乎是条死路. PHP 和 JavaScript 的最大差异是 PHP 是工作在服务器端, JavaScript 是客户端, 最常见的场景就是浏览器. Node.js 工作在服务器端也可以像 PHP 一样写爬虫, 虽然是 JavaScript 语法, 但不是我们通常说 JavaScript.
Q: 这个爬虫项目编码大概用了多久, 为什么是美女图站而不是其他?
A: 大概用了 10 小时编码和测试. 正如开头所说, 这个站不用登录验证, 遍历 HTML 结构, 相对来说容易一些. 另外是第一次写图片爬虫, 也是练手, 美女的话可能关注会多一点, 编程的话是非常缺乏交流啊, 希望多一些反馈.
Q: 项目最大的收获是什么?
A: 在 DOM 结构不行的时候, 还是正则厉害, 讲正则最好的博客作者是学 C 语言的. 最近有整理代码强迫症, 把过程式写法都整进面向对象了, 所以代码就两个 200 多行的对象, 现在感觉用过程四重循环也能搞定! 下个站准备试试.
下载地址
- https://github.com/nasaplayer/-PHP-
- - END -
codenight 改变世界的每一天
来源: https://juejin.im/entry/5b029287f265da0b95276972