失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > python爬虫爬取安居客并进行简单数据分析

python爬虫爬取安居客并进行简单数据分析

时间:2020-10-17 10:29:42

相关推荐

python爬虫爬取安居客并进行简单数据分析

此篇博客为普通方式爬取安居客租房数据一共提取出1200条,但是在进行大规模的数据爬取时,不建议使用这种方式,速度太慢是最大的诟病,在进行大规模爬取时,使用分布式爬虫是第一选择

爬取过程

一、指定爬取数据

二、设置请求头防止反爬

三、分析页面并且与网页源码进行比对

四、分析页面整理数据

五、保存到excel表中

六、使用jupyternotebook进行简单的数据分析

一、指定爬取数据

需求:

提取价格、面积、详细标题、名称、具体位置、房屋结构、装修情况

二、设置请求头

这里设置请求头依然使用最常见的 user-agent和cookie值作为反爬头,但是在实际操作中,由于爬取数据太快可能会导致ip被禁,一开始我也被封过一次。。。。。奇迹的是后来隔了一天打开之后就可以畅通无阻的爬取,但是最保险的方式还是设置一个代理ip防止被封免费的代理大家可以去快代理去尝试,土豪就除外了。

三、分析页面与源码比对

通过对源码的分析,发现页面对数字进行了一个加密。如图

接下来就要对字体进行一个解密

通过查看网页得知,网页上所有的数字都进行了加密,因此提取价格以及房屋结构首先都要对数字进行解密

第一步 分析

字体加密一般都涉及到字体文件,字体文件后面一般为 woff和ttf,字体文件可以在网页源码中找到

在这里我们看到了base64说明这些字符串都是通过base64编码过,这些字符串就是字体映射的内容

第二步 创建、打开文件,查找映射关系

1.创建文件代码

fontdata = re.findall("charset=utf-8;base64,(.*?)'\) format",html,re.S)[0]fontent = base64.b64decode(fontdata)f = open("t5.woff", 'wb')f.write(fontent)f.close()`

fontdata为bs64编码过后的字符串

2.用TTFont打开文件并保存为xml格式

fonts = TTFont('t5.woff')fonts.saveXML('test8.xml')

3.查看文件并找到索引关系

<cmap><tableVersion version="0"/><cmap_format_4 platformID="0" platEncID="3" language="0"><map code="0x9476" name="glyph00008"/><!-- CJK UNIFIED IDEOGRAPH-9476 --><map code="0x958f" name="glyph00003"/><!-- CJK UNIFIED IDEOGRAPH-958F --><map code="0x993c" name="glyph00002"/><!-- CJK UNIFIED IDEOGRAPH-993C --><map code="0x9a4b" name="glyph00006"/><!-- CJK UNIFIED IDEOGRAPH-9A4B --><map code="0x9e3a" name="glyph00009"/><!-- CJK UNIFIED IDEOGRAPH-9E3A --><map code="0x9ea3" name="glyph00005"/><!-- CJK UNIFIED IDEOGRAPH-9EA3 --><map code="0x9f64" name="glyph00010"/><!-- CJK UNIFIED IDEOGRAPH-9F64 --><map code="0x9f92" name="glyph00001"/><!-- CJK UNIFIED IDEOGRAPH-9F92 --><map code="0x9fa4" name="glyph00004"/><!-- CJK UNIFIED IDEOGRAPH-9FA4 --><map code="0x9fa5" name="glyph00007"/><!-- CJK UNIFIED IDEOGRAPH-9FA5 --><GlyphID id="0" name="glyph00000"/><GlyphID id="1" name="glyph00001"/><GlyphID id="2" name="glyph00002"/><GlyphID id="3" name="glyph00003"/><GlyphID id="4" name="glyph00004"/><GlyphID id="5" name="glyph00005"/><GlyphID id="6" name="glyph00006"/><GlyphID id="7" name="glyph00007"/><GlyphID id="8" name="glyph00008"/><GlyphID id="9" name="glyph00009"/><GlyphID id="10" name="glyph00010"/>

列如

&#x9fa4;

&#对应code码的0 code码为x9fa4的name为glyph00004,匹配name为glyph00004的id值为4,在去匹配网页对应的数字发现需要将id值减去1,因此在写代码时提取出name最后一个数字减去1就可以匹配到数字

字体反爬代码

fontdata = re.findall("charset=utf-8;base64,(.*?)'\) format",html,re.S)[0]fontent = base64.b64decode(fontdata)f = open("t5.woff", 'wb')f.write(fontent)f.close()fonts = TTFont('t5.woff')fonts.saveXML('test8.xml')root = et.parse('test8.xml').getroot()con = root.find('cmap').find('cmap_format_4').findall('map')for i in con:names = i.attrib['name']code = i.attrib['code'].replace('0x', '&#x') + ';'c1 = re.findall(r'\d+', names)c2 = str(int(c1[0]) - 1)content = content.replace(code, c2)return content

四、分析页面整理数据

将字体解密后通过分析页面就可以提取出价格、房屋结构和面积的数据,通过xpath定位的方式定位到每一个爬取数据的位置

def lxmldata(data):datas =etree.HTML(data)list1 = []date=datas.xpath("//div[@class='list-content']//div[@class='zu-itemmod']")for i,dates in enumerate (date):dict = {}#价格price1 = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)price = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)[i]#面积size = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[2:len(price1)*3:3][i]#房屋结构fangjian1 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[0:len(price1)*3:3][i]fangjian2 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[1:len(price1)*3:3][i]#详细标题title=dates.xpath(".//div[@class='zu-info']//b/text()")#名称map = dates.xpath(".//address[@class='details-item']/a/text()")#具体位置local = dates.xpath(".//address[@class='details-item']/text()")local = [x.strip() for x in local]#装修情况zhuangxiu = dates.xpath(".//p[@class='details-item bot-tag']//span[@class='cls-1']/text()")+dates.xpath(".//p[@class='details-item bot-tag']/span[@class='cls-2']/text()")+dates.xpath(".//p[@class='details-item bot-tag']/span[@class='cls-3']/text()")dict['价格']=str(fanpa1(price,data))+'元/月'dict['面积']=str(fanpa1(size,data))+'平方米'dict["详细标题"]=title[0]dict['名称']=map[0]dict["具体位置"]=local[1]dict['房间结构']=fanpa1(fangjian1,data)+'室'+fanpa1(fangjian2,data)+'厅'if len(zhuangxiu)==3:dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]+','+zhuangxiu[2]elif len(zhuangxiu)==2:dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]else:dict["装修情况"] = zhuangxiu[0]list1.append(dict)return list1

第五步 保存到excel表

设置7个字段分别为[‘价格’,‘面积’,‘详细标题’,‘名称’,‘具体位置’,‘房间结构’,‘装修情况’]

代码如下

def save(list):filename = "C:/Users/xxx/Desktop/安居客二十页.xls"book = xlwt.Workbook()sheet1=book.add_sheet("sheet1")header = ['价格','面积','详细标题','名称','具体位置','房间大小','装修情况']for i in range(len(header)):sheet1.write(0,i,header[i])j = 1for i in list:sheet1.write(j,0,i['价格'])sheet1.write(j,1,i['面积'])sheet1.write(j,2,i['详细标题'])sheet1.write(j,3,i['名称'])sheet1.write(j,4,i['具体位置'])sheet1.write(j,5,i['房间大小'])sheet1.write(j,6,i['装修情况'])j = j+1book.save(filename)print("写入成功")

list是传入的数据,list=lxmldata

总代码

import requestsfrom lxml import etreeimport randomimport timefrom selenium import webdriverimport base64import base64import reimport xml.etree.ElementTree as etfrom fontTools.ttLib import TTFontfrom fontTools.ttLib import TTFontimport xlwt#字体反扒def fanpa1(content,html):fontdata = re.findall("charset=utf-8;base64,(.*?)'\) format",html,re.S)[0]fontent = base64.b64decode(fontdata)f = open("t5.woff", 'wb')f.write(fontent)f.close()fonts = TTFont('t5.woff')fonts.saveXML('test8.xml')root = et.parse('test8.xml').getroot()con = root.find('cmap').find('cmap_format_4').findall('map')for i in con:names = i.attrib['name']code = i.attrib['code'].replace('0x', '&#x') + ';'c1 = re.findall(r'\d+', names)c2 = str(int(c1[0]) - 1)content = content.replace(code, c2)return content#分析页面def lxmldata(data):datas =etree.HTML(data)list1 = []date=datas.xpath("//div[@class='list-content']//div[@class='zu-itemmod']")for i,dates in enumerate (date):dict = {}#价格price1 = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)price = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)[i]#面积size = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[2:len(price1)*3:3][i]#房屋结构fangjian1 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[0:len(price1)*3:3][i]fangjian2 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[1:len(price1)*3:3][i]#详细标题title=dates.xpath(".//div[@class='zu-info']//b/text()")#名称map = dates.xpath(".//address[@class='details-item']/a/text()")#具体位置local = dates.xpath(".//address[@class='details-item']/text()")local = [x.strip() for x in local]#装修情况zhuangxiu = dates.xpath(".//p[@class='details-item bot-tag']//span[@class='cls-1']/text()")+dates.xpath(".//p[@class='details-item bot-tag']/span[@class='cls-2']/text()")+dates.xpath(".//p[@class='details-item bot-tag']/span[@class='cls-3']/text()")dict['价格']=str(fanpa1(price,data))+'元/月'dict['面积']=str(fanpa1(size,data))+'平方米'dict["详细标题"]=title[0]dict['名称']=map[0]dict["具体位置"]=local[1]dict['房间结构']=fanpa1(fangjian1,data)+'室'+fanpa1(fangjian2,data)+'厅'if len(zhuangxiu)==3:dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]+','+zhuangxiu[2]elif len(zhuangxiu)==2:dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]else:dict["装修情况"] = zhuangxiu[0]list1.append(dict)return list1def save(list):filename = "C:/Users/孟尚宇/Desktop/安居客二十页.xls"book = xlwt.Workbook()sheet1=book.add_sheet("sheet1")header = ['价格','面积','详细标题','名称','具体位置','房间大小','装修情况']for i in range(len(header)):sheet1.write(0,i,header[i])j = 1for i in list:sheet1.write(j,0,i['价格'])sheet1.write(j,1,i['面积'])sheet1.write(j,2,i['详细标题'])sheet1.write(j,3,i['名称'])sheet1.write(j,4,i['具体位置'])sheet1.write(j,5,i['房间大小'])sheet1.write(j,6,i['装修情况'])j = j+1book.save(filename)print("写入成功")if __name__ == '__main__':headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36","cookie":"aQQ_ajkguid=C1CC68B8-4D19-287F-3644-2D367108DEC0; id58=e87rkF/LkOJmpXJnEm4JAg==; 58tj_uuid=a6d935e2-5506-4369-9370-d4081b424818; ctid=49; _ga=GA1.2.1998955085.1607386984; _gid=GA1.2.1925540573.1607386984; new_uv=2; als=0; cmctid=2053; wmda_new_uuid=1; wmda_uuid=aa760fc62c405eecb84c273b7206beed; wmda_visited_projects=%3B6289197098934; xxzl_cid=090b7011f13f44c8b3d9271ce16587b3; xzuid=ad62da25-6302-4e3e-992e-eea22f2d9d02; lps=https%3A%2F%2Fhai.%2Ffangyuan%2Fp2%2F%3Ffrom_price%3D0%26to_price%3D2500an%7Chttps%3A%2F%%2F; wmda_session_id_6289197098934=1607426591062-bdd0135e-4c1f-a60c; xzfzqtoken=lbhfULbvUI2tmDmR%2By8o2XgL%2FoD%2Fi8pTDHftNbKQZZ3J9dDc2%2BiE91mVlKbcur5Hin35brBb%2F%2FeSODvMgkQULA%3D%3D","path":"/fangyuan/p2/?from_price=0&to_price=2500an"}dict2 = []dict1 = []for i in range(20):url = "https://hai./fangyuan/p{}/".format(i+1)resopnse=requests.get(url=url,headers=headers).content.decode('utf-8')list=lxmldata(resopnse)dict1.append(list)print("第"+str(i)+"页数据完成")for j in dict1:for k in j:dict2.append(k)save(dict2)

第六步进行简单的数据分析

分析目标:挑选出安居客2000-4000的并且面积大于100平米的房子

第一步导入数据

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltdata2=pd.read_excel(r"C:\Users\xxx\Desktop\安居客二十页.xls")

第二步 找出详细标题重复值并删掉

data2.drop_duplicates(subset=['详细标题'],inplace=True)

第三步删除存在缺失值的某行

data2.dropna(how='any',axis=0)

第四步 挑选出有电梯的房子

定义一个函数如果有电梯在’房屋结构’这一字段数据中,则返回True

之后用布尔索引挑选出数据

def home(s):if '有电梯' in s:return Trueelse:return Falsedata2['房屋结构']=data2['房屋结构'].map(home)data2=data2[data2['房屋结构']==1]

第五步 找出 三室一厅 三室二厅的房子

data2=data2[(data2['房间大小']=='3室2厅') | (data2['房间大小']=='3室1厅')]

第六步对价格进行分类

对价格分类 500-1000 1000-2000 2000-3000 3000 -4000 4000+

#把字符串后的汉字去掉data2['价格']=data2['价格'].str.split("元",expand=True).iloc[:,0]data2['价格']=data2['价格'].astype(int)grooups=pd.cut(data2['价格'],bins=[500,1000,2000,3000,4000,10000],labels = ['500-1000','1000-2000','2000-3000','3000-4000','4000+'])data2['价格范围']=grooups

第七步 找出价格为2000-4000的并且面积大于100平米的房子

data2= data2[(data2['价格范围']=='2000-3000')| (data2['价格范围']=='3000-4000')]data2['面积']=data2['面积'].str.split("平",expand=True).iloc[:,0]data2['面积']=data2['面积'].astype(float)groups=pd.cut(data2['面积'],bins = [0,100,100000000000000],labels=['0-100','100-'])data2['面积范围']=groups

第八步 根据序号找出对应的数据

s=data2[data2['面积范围']=='100-'].indexdata=pd.read_excel(r"C:\Users\xxx\Desktop\安居客二十页.xls")a=list(s)a = tuple(a)data3=data.loc[a,:]

如果觉得《python爬虫爬取安居客并进行简单数据分析》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。