学习记录:搜房网新楼盘信息爬虫

目标:爬取海南搜房网上的海南新楼盘信息

一、搜集待爬取的目标网址

先打开海南搜房网进入新楼盘页面进行研究,
http://newhouse.hn.fang.com/
但是这个页面主要是信息聚合呈现,新楼盘信息并不全,接着找到列表页,
http://newhouse.hn.fang.com/house/s/
这回是想要的了。
经研究发现该列表页的网址加上分页为如下形式,分页共有28页,分页字段主要是在/b91/这部分
从b91到b928,这样如果把这28页爬完就能初步得到全部新楼盘条目,接着再对每个新楼盘的主页进行爬取提取信息,就能得到想要的内容。
http://newhouse.hn.fang.com/house/s/b91/?ctm=1.hn.xf_search.page.1
具体某个楼盘主页为:
http://zhongyangwenhuachengld.fang.com
楼盘详情页为:
http://zhongyangwenhuachengld.fang.com/house/5011126788/housedetail.htm
开始写代码,先导入依赖的库

import requests
import re
from bs4 import BeautifulSoup

写了一个函数用于提取某个页面中包含的所有不重复链接,返回一个列表

def get_page_urls(url,regular="\w+"):
    if url is None:
        return None
    new_urls = set()
    headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/5.0.2.2000 Chrome/47.0.2526.73 Safari/537.36' }
    r = requests.get(url,headers=headers,timeout=None)
    if r.status_code == 200:
        soup = BeautifulSoup(r.text, 'html.parser',from_encoding='utf-8')
        links = soup.find_all('a', href=re.compile(r'%s' % regular))
        for link in links:
            new_url = link['href']
            new_urls.add(new_url)
            return list(new_urls)

没想到在去重这部分花了很多时间。
开始对于每一个列表页面进行下载和解析,解析页面内所有的标签,将链接地址提取出来,这里使用的正则表达式如下:

^https?://\w+.fang.com/$

将提取到的网址列表先存入一个set(),保证在一个页面上抓到的网址没有重复,抓取完后再将该集合转成list存入一个整体的网址列表中。
然后对全部网址进行去除重复,这里要去掉的重复网址是指页面上其他的非楼盘链接,由于每一个楼盘列表页都会有这些重复的信息,一共抓了28页说明会有28个重复,因此要想办法去除这一部分的链接。
想来想去,想出先找出重复的网址,保存进一个列表中,然后再将全部网址列表跟重复网址列表进行比较,若有相同项则从全部网址列表中删除重复网址项,这样就能得出最后想要的每个新楼盘主页。重点代码为:

if all_urls.count(housepage) > 1:

总觉得这样做是个笨办法效率不高,因为有重复操作,不知道有没有更方便的算法,目前想不出来。
经过一番提取去重后,得到一个所有楼盘详情页链接的文本文件,用于后续信息抓取。保存的代码为:

with open('soufangwang-detail.txt','w',encoding='utf-8') as f:
    for i in all_detail_urls:
        f.write(i)
        f.write("\n")

二、抓取信息

首先研究了一下楼盘详情页结构,想爬取的结构信息是如下这样的,每条信息在一条li的下面有两个

,第一个是信息名称,第二个是信息值,90%的信息都是这样的结构,除了部分标题,主图等:

  • 交房时间:
    预计2017年6月30日A#、B#、C#交房
  • 开始的想法是针对信息条目,一条条分析进行抓取,根据每个想要的信息构造对应的抓取函数:

    name_node = soup.find('h1').find('a',class_="ts_linear")
    data["楼盘名称"] = name_node.get_text()
    address_node = soup.find('div',string = re.compile("楼盘地址")).find_next('div')
    data["楼盘地址"] = address_node.get_text()
    

    但是这样做,首先是发现如果有的信息名称是三个字的话,搜房网会在中间插入i标签,像下面的例子,导致抓取函数无法抓取到正确的

  • 率:
    3.50
  • 于是在这里研究了好久,先是各种换搜索正则表达式,怎么都搜不到,后来突发奇想,能不能在抓取之前把所有的i标签去掉,于是查文档,写了如下代码

    soup = BeautifulSoup(r.text, 'html.parser')
        for tag_i in soup.findAll('i'):
        tag_i.decompose()
    

    这样先对下载到的文档进行处理再抓取应该是可以的,但是很奇怪,去掉i标签后文字还是无法查找到,这回真的卡壳了。
    然后经过一番冥思苦想,忽然想到,干嘛要一个个信息来针对性抓取啊,既然它结构大部分都是相同的,干脆全部抓取出来存入一个字典里好了。于是开始写代码:

    data = {}
    key_nodes = soup.findAll('div', class_="list-left")
    for key_node in key_nodes:
        key = key_node.get_text().replace("\t","").replace("\n","").replace("\r","").replace(":","").strip()
        value_node = key_node.find_next('div')
        value = value_node.get_text().replace("\t","").replace("\n","").replace("\r","").strip()
        data[key] = value
    

    抓取成功!发现这样做不光效率高,而且既方便又能容错,获得的信息也全,唉怎么不早点想到呢,折腾好久。
    另外在页面结构中发现有一个

    先初步写了个节点抓取语句,成功找到该

    你可能感兴趣的:(学习记录:搜房网新楼盘信息爬虫)