链家小区数据爬取

这次爬取链家数据时爬取的链家北京区域的所有小区数据。
区域比较少,手动去把每个区的列表页面罗列了出来(所有分区全家起来288个)
没有去处理当前总共多少页,之类的数据,而是把这个数据导入到一张表里,表字段设计了页数和当前爬取的页码,这样方便重试,也不做无用功跑已经跑过的数据。
由于一开始只需要小区的名称,地址,当前均价等,这些信息都有了,所以也没有去爬详情。
列表页面的URL格式为:https://bj.lianjia.com/xiaoqu/guangqumen/
默认为第一页,首页之后的格式均为在当前URL后面添加 pg+pageNo+/ 。
String realUrl = baseUrl + “pg” + pageNo + “/”;
通过写好的可以使用代理的HttpClient发起请求,列表页还是很容易请求成功的。
然后使用Jsoup解析请求到的网页字符串(据大神说,用XPath更高端更牛皮,不过我用着Jsoup还很顺手,就暂时不换了 – 主要以前用jquery习惯,所以找起来也方便)
import org.jsoup.Jsoup;
Document doc = Jsoup.parse(html);
打开网页调试工具,找到翻页位置的元素,发现:翻页的所有链接都在li[class=house-lst-page-box]元素内的超链接标签<a>上,并且最后一个超链接标签就是最大页码的标签,标签上的属性 data-page 就是页码,也就是最大页数,正好提取出来
代码:
Elements pageList = doc.select(“li[class=house-lst-page-box]”).select(“a”);
Element a = Safes.first(Lists.reverse(pageList));
Integer pageCount = Integer.valueOf(a.attr(“data-page”));
至此最大页数和当前页都已经拿到了。接着是收集小区信息。
小区列表中每个小区的信息就在一堆class=xiaoquListItem的li元素里,包含了列表里需要的所有小区的信息,先把每个小区的块都拿到。(当时爬的时候,下面填充用的标签还用的是a标签,写文章时候已经改成div和a标签交叉的了,感觉链家也不是没有做反爬虫,只是做的比较简单,下面呈上原来的老代码)
ElementsxiaoquList=doc.select(“li[class=xiaoquListItem]”).select(“a”).select(“a[class=PageLink]”)
接下来看源码就比较清楚了,里面分了三大块,左侧是图片,中间是小区名称、最近的成交信息、地址信息、代理人信息和标签信息,放在class=info的div里,每一块信息是一个div,右侧是价格、在售信息等内容,放在class=xiaoquListItemRight的div里。
从里面分别取出来这些信息,并放到对应对象里
List<LianJiaXiaoquEntity> entityList = Lists.newArrayList();
Safes.of(xiaoquList).forEach(xiaoqu -> {
    LianJiaXiaoquEntity entity = new LianJiaXiaoquEntity();
    Element title = Safes.first(xiaoqu.select(“div[class=title]”)).selectFirst(“a”);
    entity.setName(title.text());
    entity.setUrl(title.attr(“href”));
    Optional.ofNullable(Safes.first(xiaoqu.select(“div[positionInfo]”))).ifPresent(positionInfo -> {
        positionInfo.text();// \r\n&nbsp;\r\n&nbsp;/板楼/塔板结合/r/n&nbsp;2002年建成
        entity.setNameDetail(StringUtils.join(positionInfo.select(“a”).stream().map(Element::text).collect(Collectors.toList()), “-“) + entity.getName());
    });
    Optional.ofNullable(Safes.first(xiaoqu.select(“div[class=xiaoquListItemRight]”))).ifPresent(price -> {
        entity.setAveaPrice(Safes.first(price.select(“span”)).text());
        entity.setPriceTime(Safes.first(price.select(“div[class=priceDesc]”)).text());
    });
    entityList.add(entity);
这样,就把列表里一些小区的基本信息保存下来了。
但是我需要的不只是这些,主要还需要小区的坐标,这个在列表里没有。找小区坐标的过程也是一波三折,接下来说。