最近因为工作突然变动,新的办公地点离现在的住处很远,所以不得不换房子和租金。我坐上了中介的小电驴,开始探索这个城市陌生的角落。在各种租房app之间切换的过程中,我真的有点不知所措,因为效率真的很低:一是因为和女朋友住在一起,需要同时考虑两人的通勤距离,但是每个平台都是按照上下班时间找房子的。功能比较没用。有的平台不支持同时选择多个地点,有的平台只能机械地从各个地点取相同通勤时间的点,不能满足使用需求。其次,站在租房者的角度,租房平台过多,各平台筛选排序逻辑不一致,同类房源信息难以横向比较。不过没关系,作为程序员,解决问题当然要用程序员的方法。于是,昨晚,我用python脚本获取了上海某租房平台的所有房源信息,一共两万多条:把爬取数据的全过程分享给大家。分析页面并找到入口点。首先,进入平台的租赁页面。可以看到我们需要的大部分信息已经包含在首页的listing列表中,而这些信息可以直接从dom中获取,所以可以考虑直接通过模拟请求的方式收集网页数据。https://sh.lianjia.com/zufang/那么接下来就要考虑如何获取url了。通过观察,我们发现这个区域有两万多间房子,通过网页只能访问到前100页的数据,每页显示的条目数上限为30条,相当于总共3k条,不可能获取到所有的信息。.但是我们可以通过添加过滤条件来解决这个问题。在筛选项中选择“静安”,输入以下url:https://sh.lianjia.com/zufang/jingan/可以看到该区域有2k多套房子,数据数量pages为75,每页30,理论上所有数据都可以访问。因此,通过分别获取各区的房屋数据,即可获取城市的所有数据。https://sh.lianjia.com/zufang/jingan/pg2/点击第二页按钮后,会输入上面的url。可以发现只要修改pg后面的数字,就可以输入对应的页码了。但是,这里有一个问题。每次访问相同数量的页面获取的数据是不同的,这将导致收集的数据重复。于是我们在排序条件中点击“LatestRelease”,进入如下链接:https://sh.lianjia.com/zufang/jingan/pg2rco11/这种排序方式得到的数据顺序是稳定的,至此我们的思路好了:先分别访问每个小region的第一个页面,然后通过第一个页面获取当前region的最大页面数,然后访问模拟请求访问每个页面获取所有数据。一旦有了爬取数据的想法,就需要手写代码了。首先,我们需要收集所有链接。代码如下:#所有小区对应的标识符list=['靖安','徐汇','黄浦','长宁','普陀','浦东','宝山','虹口','杨浦','闵行','金山','嘉定','崇明','奉贤','松江','青浦']#存储所有链接urls=[]forainlist:urls.append('https://sh.lianjia.com/zufang/{}/pg1rco11/'.format(a))#设置请求头避免ip被封banheaders={'User-Agent':'Mozilla/5.0(WindowsNT10.0;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/81.0.4044.9Safari/537.36'}#获取当前小区域第1页的dom信息res=requests.get('https://sh.lianjia.com/zufang/{}/pg1rco11/'.format(a),headers=headers)content=res.textsoup=BeautifulSoup(content,'html.parser')#获取当前页面最大页数page_num=int(soup.find('div',attrs={'class':'content__pg'}).attrs['data-totalpage'])foriinrange(2,page_num+1):#将所有链接保存到urlsurls.append('https://sh.lianjia.com/zufang/{}/pg{}rco11/'.format(a,i)),我们要对上一步得到的url进行一一处理,得到链接中的数据,代码如下:num=1forurlinurls:print("正在处理页面{}数据...".format(str(num)))res1=requests.get(url,headers=headers)content1=res1.textsoup1=BeautifulSoup(content1,'html.parser')infos=soup1.find('div',{'class':'content__list'}).find_all('div',{'class':'content__list--item'})通过Observing整理数据,导出文件页面结构,我们可以得到每个元素的存储位置,找到对应的页面元素,得到我们需要的信息。这是完整的代码。有兴趣的朋友可以根据自己的需要进行更换。链接中的区域标识和小区域标识,可以得到自己所在区域的信息。其他租房平台的爬取方式大同小异,这里不再赘述。导入时间,重新,csv,请求从bs4导入编解码器codecs.BOM_UTF8)f=open(r'..\sh.csv','w+',newline='',encoding='utf-8')writer=csv.writer(f)urls=[]#allsmall区域对应标识列表=['靖安','徐汇','黄浦','长宁','普陀','浦东','宝山','虹口','杨浦','闵行','金山','嘉定','崇明','奉贤','松江','青浦']#存储所有链接urls=[]forainlist:urls.append('https://sh.lianjia.com/zufang/{}/pg1rco11/'.format(a))#设置请求头以避免ip被禁止headers={'User-Agent':'Mozilla/5.0(WindowsNT10.0;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/81.0.4044.9Safari/537.36'}#获取当前小区域第1页的dom信息res=requests.get('https://sh.lianjia.com/zufang/{}/pg1rco11/'.format(a),headers=headers)content=res.textsoup=BeautifulSoup(content,'html.parser')#获取最大值当前页面的最大页数page_num=int(soup.find('div',attrs={'class':'content__pg'}).attrs['data-totalpage'])foriinrange(2,page_num+1):#保存所有链接到urlsurls.append('https://sh.lianjia.com/zufang/{}/pg{}rco11/'.format(a,i))num=1forurlinurls:#模拟请求print("Processingdataonpage{}...".format(str(num)))res1=requests.get(url,headers=headers)content1=res1.textsoup1=BeautifulSoup(content1,'html.parser')#读取页面中的数据infos=soup1.find('div',{'class':'content__list'}).find_all('div',{'class':'content__list--item'})#infos中info的数据处理:house_url='https://sh.lianjia.com'+info.a['href']title=info.find('p',{'class':'content__list--item--title'}).find('a').get_text().strip()group=title.split()[0][3:]price=info.find('span',{'class':'content__list--item-price'}).get_text()tag=info.find('p',{'class':'content__list--item--bottomoneline'}).get_text()mixed=info.find('p',{'class':'content__list--item--des'}).get_text()mix=re.split(r'/',mixed)address=mix[0].strip()area=mix[1].strip()door_orientation=mix[2].strip()style=mix[-1].strip()region=re.split(r'-',address)[0]writer.writerow((house_url,title,group,price,area,address,door_orientation,style,tag,region))time.sleep(0)print("第{}页数据处理完毕,共{}条数据".format(str(num),len(infos)))num+=1f.close()print("****全部完成****")经过一番操作,我们得到了本地各个租房平台的完整房源信息。至此,我们已经可以通过一些基本的筛选手段,得到我们所需要的数据。
