365Tools
发布时间:2024-03-13 10:30:01
本节使用 Python 爬虫库完成链家二手房(https://bj.lianjia.com/ershoufang/rs/)房源信息抓取,包括楼层、区域、总价、单价等信息。在编写此程序的过程中,您将体会到 lxml 解析库的实际应用。第一页:https://bj.lianjia.com/ershoufang/pg1/ 第二页:https://bj.lianjia.com/ershoufang/pg2/ 第三页:https://bj.lianjia.com/ershoufang/pg3/ 第n页:https://bj.lianjia.com/ershoufang/pgn/
2室1厅 | 88.62平米 | 北 南 | 简装 | 顶层(共6层) | 2004年建 | 板楼26人关注 / 7天以前发布近地铁VR看装修房本满五年随时看房225万单价25390元/平米
而每个页面中都包含 30 个房源,因此我们要匹配以下节点的父节点或者先辈节点,从而确定 Xpath 基准表达式:........
通过页面结构分析可以得出每页的 30 个房源信息全部包含以下节点中:
li标签的class属性值发生了变化,其结果如下:Ctrl+F分别对 class 变化前后的属性值进行检索,最后发现源码页只存在如下属性:
class="clear LOGVIEWDATA LOGCLICKDATA"因此 Xpath 基准表达式如下所示:
//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]
小区名称:name_list=h.xpath('.//a[@data-el="region"]/text()')
房屋介绍:info_list=h.xpath('.//div[@class="houseInfo"]/text()')
地址信息:address_list=h.xpath('.//div[@class="positionInfo"]/a/text()')
单价信息:price_list=h.xpath('.//div[@class="unitPrice"]/span/text()')
其中房屋介绍,主要包含了以下信息:
因此,匹配出的 info_list 列表需要经过处理才能得出我们想要的数据,如下所示:2室1厅 | 88.62平米 | 北 南 | 简装 | 顶层(共6层) | 2004年建 | 板楼
#户型+面积+方位+是否精装+楼层+... ['2室1厅 | 88.62平米 | 北 南 | 简装 | 顶层(共6层) | 2004年建 | 板楼']
info_list=h.xpath('.//div[@class="houseInfo"]/text()')
if info_list:
#处理列表数据
L=info_list[0].split('|')
# ['2室1厅 ', ' 88.62平米 ', ' 北 南 ', ' 简装 ', ' 顶层(共6层) ', ' 2004年建 ', ' 板楼']
if len(L) >= 5:
item['model']=L[0].strip()
item['area']=L[1].strip()
item['direction']=L[2].strip()
item['perfect']=L[3].strip()
item['floor']=L[4].strip()
#coding:utf8
import requests
import random
from lxml import etree
import time
#提供ua信息的的包
from fake_useragent import UserAgent
class LinajiaSpider(object):
def __init__(self):
self.url='https://bj.lianjia.com/ershoufang/pg{}/'
#计数,请求一个页面的次数,初始值为1
self.blog=1
# 随机取一个UA
def get_header(self):
#实例化ua对象
ua=UserAgent()
headers={'User-Agent':ua.random}
return headers
#发送请求
def get_html(self,url):
#在超时间内,对于失败页面尝试请求三次
if self.blog= 5:
item['model']=L[0].strip()
item['area']=L[1].strip()
item['direction']=L[2].strip()
item['perfect']=L[3].strip()
item['floor']=L[4].strip()
#区域+总价+单价
address_list=h.xpath('.//div[@class="positionInfo"]/a/text()')
item['address']=address_list[0].strip() if address_list else None
total_list=h.xpath('.//div[@class="totalPrice"]/span/text()')
item['total_list']=total_list[0].strip() if total_list else None
price_list=h.xpath('.//div[@class="unitPrice"]/span/text()')
item['price_list']=price_list[0].strip() if price_list else None
print(item)
# 入口函数
def run(self):
try:
for i in range(1,101):
url=self.url.format(i)
self.parse_html(url)
time.sleep(random.randint(1,3))
#每次抓取一页要初始化一次self.blog
self.blog=1
except Exception as e:
print('发生错误',e)
if __name__ == '__main__':
spider=LinajiaSpider()
spider.run()
展示部分输出结果:
{'name': '玉竹园 ', 'model': '2室1厅', 'area': '88.62平米', 'direction': '北 南', 'perfect': '简装', 'floor': '顶层(共6层)', 'address': '玉竹园', 'total_list': '225', 'price_list': '单价25390元/平米'}
{'name': '摩卡空间 ', 'model': '2室1厅', 'area': '71.95平米', 'direction': '东南', 'perfect': '简装', 'floor': '高楼层(共17层)', 'address': '摩卡空间', 'total_list': '372', 'price_list': '单价51703元/平米'}
{'name': '长城国际 ', 'model': '1室1厅', 'area': '52.73平米', 'direction': '西', 'perfect': '精装', 'floor': '22层', 'address': '长城国际', 'total_list': '235', 'price_list': '单价44567元/平米'}
{'name': '牛街西里 ', 'model': '3室1厅', 'area': '102.6平米', 'direction': '东北', 'perfect': '其他', 'floor': '中楼层(共20层)', 'address': '牛街西里', 'total_list': '815', 'price_list': '单价79435元/平米'}
{'name': '新安里 ', 'model': '1室2厅', 'area': '51.56平米', 'direction': '南 北', 'perfect': '精装', 'floor': '顶层(共6层)', 'address': '新安里', 'total_list': '197', 'price_list': '单价38208元/平米'}
{'name': '龙华园 ', 'model': '2室1厅', 'area': '67.73平米', 'direction': '南 北', 'perfect': '简装', 'floor': '顶层(共6层)', 'address': '龙华园', 'total_list': '342', 'price_list': '单价50495元/平米'}
...