Scrapy实战篇(一)之爬取链家网成交房源数据(上)

举报
格图洛书 发表于 2021/12/30 01:53:19 2021/12/30
【摘要】 今天,我们就以链家网南京地区为例,来学习爬取链家网的成交房源数据。 这里推荐使用火狐浏览器,并且安装firebug和firepath两款插件,你会发现,这两款插件会给我们后续的数据提取带来很大的方便。 首先创建一个名称为lianjia的项目。 需求分析 爬取数据的第一步当然是确定我们的需求,大方向就是我们想拿到南京地区的房源成交信息,但...

今天,我们就以链家网南京地区为例,来学习爬取链家网的成交房源数据。

这里推荐使用火狐浏览器,并且安装firebug和firepath两款插件,你会发现,这两款插件会给我们后续的数据提取带来很大的方便。

首先创建一个名称为lianjia的项目。

需求分析

爬取数据的第一步当然是确定我们的需求,大方向就是我们想拿到南京地区的房源成交信息,但是具体的细节信息,我们需要从网页来看,,我们直接在浏览器中输入以下的网址https://nj.lianjia.com/chengjiao/,会显示南京地区的成交的房源信息,包括名称,房屋简介,地理位置,成交日期,成交价格,成交单价等详细信息,这样我们就确定了我们想要的信息,我们在items.py文件中定义如下的一些字段。


  
  1. #items.py
  2. from scrapy import Item,Field
  3. class LianjiaItem(Item):
  4. region = Field() #行政区域
  5. href = Field() #房源链接
  6. name = Field() #房源名称
  7. style = Field() #房源结构
  8. area = Field() #小区
  9. orientation = Field() #朝向
  10. decoration = Field() #装修
  11. elevator = Field() #电梯
  12. floor = Field() #楼层高度
  13. build_year = Field() #建造时间
  14. sign_time = Field() #签约时间
  15. unit_price = Field() #每平米单价
  16. total_price = Field() #总价
  17. fangchan_class = Field() #房产类型
  18. school = Field() #周边学校
  19. subway = Field() #周边地铁

请注意,以上的信息,并不是每一套房源都有的,比如下面的地铁,学校,很多房源都是没有的。

问题

  • 你会发现一个问题,每一个页面会呈现30条的房源信息,最下面一共可以显示100页,总计最多也就是3000条信息,南京地区的成交房源信息肯定不止这区区的3000条,那么如果直接从这个页面通过翻页来获取数据,最多只能获取到3000条信息,所以我们这里需要转思路。

  • 还是这个页面,可以看到页面上部列出了南京地区的行政区,我们随意选择一个,会发现,新的页面依然是每一页30条,共计100页,但是我们有11个行政区,那么其数量也是翻了好几倍了。

  • 这个时候,你可能还是不满足,我们想办法看一下是不是还可以进一步向下划分,没错那就是小区,我们把房源从11个行政区划分到小区上,以小区为单位,每一个小区上面还有房源数据,这样的话,我们的信息可以说比较全面了,当然了,我们需要做的工作也是要翻倍的。

总结

这里我们通过分析,总结出了如下的思路:

  • 以行政区为单位,先获取南京地区所有的小区信息
  • 以小区为单位,获取每一个小区里面的房源数据
  • 最后就是获取具体的每一个房源的信息。

具体实施

现在明确了我们的思路,下面就开始具体的实施。

编写spider.py文件


  
  1. from scrapy import Spider,Request
  2. import re
  3. from lxml import etree
  4. import json
  5. from urllib.parse import quote
  6. from lianjia.items import LianjiaItem
  7. class Lianjia_spider(Spider):
  8. name = 'lianjia'
  9. allowed_domains = ['nj.lianjia.com']
  10. regions = {'gulou':'鼓楼',
  11. 'jianye':'建邺',
  12. 'qinhuai':'秦淮',
  13. 'xuanwu':'玄武',
  14. 'yuhuatai':'雨花台',
  15. 'qixia':'栖霞',
  16. 'jiangning':'江宁',
  17. 'liuhe':'六合',
  18. 'pukou':'浦口',
  19. 'lishui':'涟水',
  20. 'gaochun':'高淳'
  21. }
  22. def start_requests(self):
  23. for region in list(self.regions.keys()):
  24. url = "https://nj.lianjia.com/xiaoqu/" + region + "/"
  25. yield Request(url=url, callback=self.parse, meta={'region':region}) #用来获取页码
  26. def parse(self, response):
  27. region = response.meta['region']
  28. selector = etree.HTML(response.text)
  29. sel = selector.xpath("//div[@class='page-box house-lst-page-box']/@page-data")[0] # 返回的是字符串字典
  30. sel = json.loads(sel) # 转化为字典
  31. total_pages = sel.get("totalPage")
  32. for i in range(int(total_pages)):
  33. url_page = "https://nj.lianjia.com/xiaoqu/{}/pg{}/".format(region, str(i + 1))
  34. yield Request(url=url_page, callback=self.parse_xiaoqu, meta={'region':region})
  35. def parse_xiaoqu(self,response):
  36. selector = etree.HTML(response.text)
  37. xiaoqu_list = selector.xpath('//ul[@class="listContent"]//li//div[@class="title"]/a/text()')
  38. for xq_name in xiaoqu_list:
  39. url = "https://nj.lianjia.com/chengjiao/rs" + quote(xq_name) + "/"
  40. yield Request(url=url, callback=self.parse_chengjiao, meta={'xq_name':xq_name,
  41. 'region':response.meta['region']})
  42. def parse_chengjiao(self,response):
  43. xq_name = response.meta['xq_name']
  44. selector = etree.HTML(response.text)
  45. content = selector.xpath("//div[@class='page-box house-lst-page-box']") #有可能为空
  46. total_pages = 0
  47. if len(content):
  48. page_data = json.loads(content[0].xpath('./@page-data')[0])
  49. total_pages = page_data.get("totalPage") # 获取总的页面数量
  50. for i in range(int(total_pages)):
  51. url_page = "https://nj.lianjia.com/chengjiao/pg{}rs{}/".format(str(i+1), quote(xq_name))
  52. yield Request(url=url_page, callback=self.parse_content, meta={'region': response.meta['region']})
  53. def parse_content(self,response):
  54. selector = etree.HTML(response.text)
  55. cj_list = selector.xpath("//ul[@class='listContent']/li")
  56. for cj in cj_list:
  57. item = LianjiaItem()
  58. item['region'] = self.regions.get(response.meta['region'])
  59. href = cj.xpath('./a/@href')
  60. if not len(href):
  61. continue
  62. item['href'] = href[0]
  63. content = cj.xpath('.//div[@class="title"]/a/text()')
  64. if len(content):
  65. content = content[0].split() # 按照空格分割成一个列表
  66. item['name'] = content[0]
  67. item['style'] = content[1]
  68. item['area'] = content[2]
  69. content = cj.xpath('.//div[@class="houseInfo"]/text()')
  70. if len(content):
  71. content = content[0].split('|')
  72. item['orientation'] = content[0]
  73. item['decoration'] = content[1]
  74. if len(content) == 3:
  75. item['elevator'] = content[2]
  76. else:
  77. item['elevator'] = '无'
  78. content = cj.xpath('.//div[@class="positionInfo"]/text()')
  79. if len(content):
  80. content = content[0].split()
  81. item['floor'] = content[0]
  82. if len(content) == 2:
  83. item['build_year'] = content[1]
  84. else:
  85. item['build_year'] = '无'
  86. content = cj.xpath('.//div[@class="dealDate"]/text()')
  87. if len(content):
  88. item['sign_time'] = content[0]
  89. content = cj.xpath('.//div[@class="totalPrice"]/span/text()')
  90. if len(content):
  91. item['total_price'] = content[0]
  92. content = cj.xpath('.//div[@class="unitPrice"]/span/text()')
  93. if len(content):
  94. item['unit_price'] = content[0]
  95. content = cj.xpath('.//span[@class="dealHouseTxt"]/span/text()')
  96. if len(content):
  97. for i in content:
  98. if i.find("房屋满") != -1: # 找到了返回的是非-1得数,找不到的返回的是-1
  99. item['fangchan_class'] = i
  100. elif i.find("号线") != -1:
  101. item['subway'] = i
  102. elif i.find("学") != -1:
  103. item['school'] = i
  104. yield item

我们对上面关键的地方进行解释:

  • start_requests
    这个就是我们以行政区为单位,目的是爬取每一个行政区的小区列表。
  • parse
    对行政区返回的response进行解析,我们目的是拿到这个大的行政区,包含多少个页面,其中的
    total_pages就是具体的页面数,接下来就是按照页码请求每一个页面。
  • parse_xiaoqu
    上面返回了每一个页面的信息,这个时候我们就把当前页面的小区列表拿到,而后,在针对小区列表,每一个小区进行一次请求。
  • parse_chengjiao
    解析小区的页面数,上面说到了,我们请求了每一个小区数据,这个小区肯定不止包含一页的数据,那么我们这个方法就是将这个小区包含的页面数抽取出来,而后针对每一个页面进行请求
  • parse_content
    这个方法就是解析具体的页面了,可以看到,这个方法里面包含了非常多的条件判断,这是因为,我们之前定义的item字段里面的信息,并不是每一个小区都有的,就是说,我们要的信息他不是一个规规矩矩的信息,很多的房源没有提供相关的信息,比如地铁,周边学校等等的信息,我们这里就是如果有这个信息,我们就把它提取出来,如果没有的话,我们就给他自定义一个内容
    。最后将item提交给item pipeline进行后续的处理。

由于这一节的信息比较多,我们就把它分为两个小节,在下一节中,我们对拿到的数据进行后续的处理。

文章来源: wenyusuran.blog.csdn.net,作者:文宇肃然,版权归原作者所有,如需转载,请联系作者。

原文链接:wenyusuran.blog.csdn.net/article/details/80965394

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。