写点什么

Python 爬虫实战 (一) 爬取自如网租房信息

用户头像
U+2647
关注
发布于: 2021 年 04 月 19 日

免责声明:本文仅供学习交流,如出现任何法律问题本人概不负责!

0. 前言

与自如网奋战了 2 个周,终于有点结果了。

1. 隐藏的价格信息

打开自如网(http://www.ziroom.com/z/nl/z2.html?qwd=),直接 F12 看了一下房屋列表的源码:


  <div class="priceDetail">    <p value="" class="price">    <span class="gray-6"> (每月) <span class="hui_icon"><img width="60" height="18"     src="//static8.ziroom.com/phoenix/pc/images/201810/img_label5.png" /></span> </span> </p>    <p class="more">    <a href="//www.ziroom.com/z/vr/62035032.html" target="_blank">查看更多</a></p>   </div>
复制代码


找到了房屋详情的地址(www.ziroom.com/z/vr/62035032.html),但是价格信息没有找到,没办法,到详情里找一下,发现价格信息的源码如下:


  <span class="price"> <b></b>   <span class="room_price" id="room_price"></span>  <span class="gray-6">/月(季付)</span> </span> 
复制代码


源码里竟然没有价格信息,然后在审查元素,发现价格信息应该是动态加载的。而且用的还是背景图数字。



打开这个图片的连接看一下(http://static8.ziroom.com/phoenix/pc/images/price/81c4fe87c108f9515c4ee4bafff68529s.png)



不错,已经找到了价格的初始信息,下面打算提取图片中的数字,然后根据 html 里的偏移量计算出真正的价格。

2. 图片反 OCR 识别

图片信息提取,首先想到的 就是 OCR 识别,而且都是很标准的数字,本来以为难度级别属于 hello world 级别的,但是万万没想到低估了自如网的反爬虫工作


使用 OCR 识别,一顿操作猛如虎,发现竟然识别不了,直到我把图片转换成纯黑白的,然后才发现了问题。


    url = 'http://static8.ziroom.com/phoenix/pc/images/price/9bbd4bf71c11e7c8149485d9f1ec5adbs.png'    response = requests.get(url)    im = Image.open(io.BytesIO(response.content))    im = im.convert('1')    im.show()
复制代码


发现图片竟然是下面这种镂空的,难怪 OCR 识别不出来



这就有点尴尬了,看到这种图片首先想到的就是 TensorFlow 搞一波图像识别,不过,一个小小的爬虫而已不至于用这么先进的武器吧(其实是我不会而已!^_-),然后又找了几张这种数字图片,对比之下发现,所有的图片,只要数字相同,镂空的规律是一样的,换句话说,所有图片中的数字 1 都是一种镂空的规律!!! 这就有点意思了,首先想到的就是把图片转成矩阵,然后把矩阵和具体的数字做好映射,持久化下来,之后再次请求到图片,拿图片里的矩阵与持久化后的矩阵做对比,这样就能够解析出图片里的数字了。


def analyze_img():    url = 'http://static8.ziroom.com/phoenix/pc/images/price/9bbd4bf71c11e7c8149485d9f1ec5adbs.png'    response = requests.get(url)    im = Image.open(io.BytesIO(response.content))    im = im.convert('1')    im.show()    num = [0,1,4,8,9,3,6,2,7,5]    num_dict = {}    for i in range(10):        data = im.crop((i*30,0,(i+1)*30,30)).getdata()        data = np.matrix(data,dtype='int')/255        num_dict[num[i]] =data
fp = open('num_dict.num', 'wb') pickle.dump(num_dict, fp, protocol=-1) fp.close() return num_dict
复制代码


嗯,买迈进了一小步。不太明白为什么这个图片在镂空的时候没有加一些随机的元素。如果说是由于随机之后出现极端的情况导致不容易被人眼识别,但是可以随机出一个或者两个具体的位置,随机的镂空,这样既不会出现不容易被人眼识别的情况,也能很好的防止上面这种爬虫的出现。


总之,不管自如网是出于什么考虑,背景图片的数字提取是解决了。下面,就需要找一下这张图片是怎么跟房屋信息绑定的。

3. 动态加载的图片

在 F12 的 网络请求里确实找到了这张图片的请求信息,但是发现,图片的名称是随机串。而且同一个房屋信息,每次请求时的图片名称都不一样,这说明,后台是随机生成的这张图片,没有跟房屋绑定。



所以需要找一下,这张图片的请求是从什么地方发起的,请求的 URL 又是从什么地方获取的。


在 F12 里找到了这张图片的请求位置,但是对比 html 源码发现,并没有这个请求,这说明这个元素是通过 js 动态加载的。




下面就需要找一下,到底是哪个 js 加载的这些信息。重新看了一下,房屋详情页面的源码,发现源码底部,有这样一段 js 的引用。


<script type="text/javascript">   var ZRCONFIG = {    "URL_GET_LOGIN_STATE":"/user/check-login?url=",    "URL_GET_LOGIN_STATE":"/user/check-login?url=",    "URL_GET_DETAIL_STEWARD":"/detail/steward?resblock_id=",    "URL_GET_DETAIL_INFO":"/detail/info?",    "PAGE":"detail"  };</script>      <script  type="text/javascript" src="//static8.ziroom.com/fecommon/library/jquery/jquery-1.8.3.min.js"></script><script type="text/javascript" src="//static9.ziroom.com/phoenix/pc/js/2017/common.min.js?1555741850"></script><script type="text/javascript" src="//static8.ziroom.com/phoenix/pc/js/detail.min.js?1555741850"></script><script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=CB9b776692623d30a148b5c5dc2b75a6"></script><script src="//static8.ziroom.com/phoenix/pc/js/mappage.min.js" type="text/javascript"></script>
复制代码


看命名也可以猜到 'datail.min.js' 里应该有玄机。请求下这个 js 的源码看一下。终于找到了。


$.ajax({    type: "GET",    url: ZRCONFIG.URL_GET_DETAIL_INFO     + "id=" + $("#room_id").val()     + "&house_id=" + $("#house_id").val(),    success: function(data) {        if (data.code == "200") {            var dataObj = data.data;            var priceTableList = dataObj.payment;            var listArr = [];            var trClass = "";            var listStr = "";            var priceStyle = "<style>.room_price i.num{background-image:url(" + dataObj.price[0] + ");}"             + "body.ratio2 .price i.num{background-image:url(" + dataObj.price[1]             + ");}.pay_price i.num,.text_r i.num{background-image:url(" + priceTableList[0].rent[0] + ");}"             + "body.ratio2 .pay_price i.num,body.ratio2 .text_r i.num{background-image:url("             + priceTableList[0].rent[1] + ");background-size:auto 14px;}<style>";            $("head").append(priceStyle);            var priceListHtml = "";            for (var j = 0; j < dataObj.price[2].length; j++) {                priceListHtml += '<i class="num" style="background-position:-'                 + (dataObj.price[2][j] * offset_unit)                 + 'px"></i>'            }... ... (省略其他代码)
复制代码


发现这个 js 发起了一个 ajax 请求,请求成功后,不仅设置了图片背景,而且还设置了切图的偏移量。


终于看到希望了,我们可以直接请求这个 ajax 的地址,不仅能拿到图片,还能拿到价格信息对应图片上的数字的位置。


ajax 的请求地址是 url: ZRCONFIG.URL_GET_DETAIL_INFO + "id=" + $("#room_id").val() + "&house_id=" + $("#house_id").val()


其中 ZRCONFIG.URL_GET_DETAIL_INF 值在 房屋详情里的 js 里定义的 ,值为 /detail/info?


room_id 和 house_id 在房屋详情的页面里也能找到:


<input type="hidden" value="7e9285535a7687bf2e71be617cd07466" id="hide_key" /><input type="hidden" value="" id="user_sex" /><input type="hidden" value="" id="user_uid" /><input type="hidden" value="62035032" id="room_id" /><input type="hidden" value="60321330" id="house_id" /><input type="hidden" value="110000" id="current_city_code" /><input type="hidden" value="" id="ly_name" /><input type="hidden" value="" id="ly_phone" /><input type="hidden" value="1" id="house_type" /><input type="hidden" id="resblock_id" value="1111027374437"/>
复制代码


拼接后的最终的 URL 地址是 /detail/info?id=62035032&house_id=60321330


然后拼接上自如网的前缀,就是最终的请求地址,http://www.ziroom.com/detail/info?id=62035032&house_id=60321330


请求一下,终于解决了,价格信息的问题。


4. 完整思路及代码

下面的问题就简单了,循环分页,筛选出每页里的房屋详情 URL ,然后根据详情里的信息去请求价格信息,最后可以把房屋信息写到 Excel 里。就结束了


完整代码在这里

发布于: 2021 年 04 月 19 日阅读数: 23
用户头像

U+2647

关注

evolving code monkey 2018.11.05 加入

https://zdran.com/

评论

发布
暂无评论
Python 爬虫实战(一) 爬取自如网租房信息