本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

爬取过程
一、指定爬取数据
二、设置请求头防止反爬
三、分析页面并且与网页源码进行比对
四、分析页面整理数据
五、保存到excel表中
六、使用jupyternotebook进行简单的数据分析

一、指定爬取数据

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

二、设置请求头

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

三、分析页面与源码比对

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

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

第一步 分析

字体加密一般都涉及到字体文件,字体文件后面一般为 woff和ttf,字体文件可以在网页源码中找到
在这里我们看到了base64说明这些字符串都是通过base64编码过,这些字符串就是字体映射的内容

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

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

fontdata为bs64编码过后的字符串

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

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

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

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

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

字体反爬代码

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

四、分析页面整理数据

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

  1. def lxmldata(data):
  2. datas =etree.HTML(data)
  3. list1 = []
  4. date=datas.xpath("//div[@class='list-content']//div[@class='zu-itemmod']")
  5. for i,dates in enumerate (date):
  6. dict = {}
  7. #价格
  8. price1 = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)
  9. price = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)[i]
  10. #面积
  11. size = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[2:len(price1)*3:3][i]
  12. #房屋结构
  13. fangjian1 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[0:len(price1)*3:3][i]
  14. fangjian2 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[1:len(price1)*3:3][i]
  15. #详细标题
  16. title=dates.xpath(".//div[@class='zu-info']//b/text()")
  17. #名称
  18. map = dates.xpath(".//address[@class='details-item']/a/text()")
  19. #具体位置
  20. local = dates.xpath(".//address[@class='details-item']/text()")
  21. local = [x.strip() for x in local]
  22. #装修情况
  23. 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()")
  24. dict['价格']=str(fanpa1(price,data))+'元/月'
  25. dict['面积']=str(fanpa1(size,data))+'平方米'
  26. dict["详细标题"]=title[0]
  27. dict['名称']=map[0]
  28. dict["具体位置"]=local[1]
  29. dict['房间结构']=fanpa1(fangjian1,data)+'室'+fanpa1(fangjian2,data)+'厅'
  30. if len(zhuangxiu)==3:
  31. dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]+','+zhuangxiu[2]
  32. elif len(zhuangxiu)==2:
  33. dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]
  34. else:
  35. dict["装修情况"] = zhuangxiu[0]
  36. list1.append(dict)
  37. return list1

第五步 保存到excel表
设置7个字段分别为[‘价格’,‘面积’,‘详细标题’,‘名称’,‘具体位置’,‘房间结构’,‘装修情况’]
代码如下

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

list是传入的数据,list=lxmldata

总代码

  1. import requests
  2. from lxml import etree
  3. import random
  4. import time
  5. from selenium import webdriver
  6. import base64
  7. import base64
  8. import re
  9. import xml.etree.ElementTree as et
  10. from fontTools.ttLib import TTFont
  11. from fontTools.ttLib import TTFont
  12. import xlwt
  13. #字体反扒
  14. def fanpa1(content,html):
  15. fontdata = re.findall("charset=utf-8;base64,(.*?)'\) format",html,re.S)[0]
  16. fontent = base64.b64decode(fontdata)
  17. f = open("t5.woff", 'wb')
  18. f.write(fontent)
  19. f.close()
  20. fonts = TTFont('t5.woff')
  21. fonts.saveXML('test8.xml')
  22. root = et.parse('test8.xml').getroot()
  23. con = root.find('cmap').find('cmap_format_4').findall('map')
  24. for i in con:
  25. names = i.attrib['name']
  26. code = i.attrib['code'].replace('0x', '&#x') + ';'
  27. c1 = re.findall(r'\d+', names)
  28. c2 = str(int(c1[0]) - 1)
  29. content = content.replace(code, c2)
  30. return content
  31. #分析页面
  32. def lxmldata(data):
  33. datas =etree.HTML(data)
  34. list1 = []
  35. date=datas.xpath("//div[@class='list-content']//div[@class='zu-itemmod']")
  36. for i,dates in enumerate (date):
  37. dict = {}
  38. #价格
  39. price1 = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)
  40. price = re.findall('<p><strong><b class="strongbox">(.*?)</b></strong> 元/月</p>', data, re.S)[i]
  41. #面积
  42. size = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[2:len(price1)*3:3][i]
  43. #房屋结构
  44. fangjian1 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[0:len(price1)*3:3][i]
  45. fangjian2 = re.findall('<b class="strongbox" style="font-weight: normal;">(.*?)</b>', data, re.S)[1:len(price1)*3:3][i]
  46. #详细标题
  47. title=dates.xpath(".//div[@class='zu-info']//b/text()")
  48. #名称
  49. map = dates.xpath(".//address[@class='details-item']/a/text()")
  50. #具体位置
  51. local = dates.xpath(".//address[@class='details-item']/text()")
  52. local = [x.strip() for x in local]
  53. #装修情况
  54. 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()")
  55. dict['价格']=str(fanpa1(price,data))+'元/月'
  56. dict['面积']=str(fanpa1(size,data))+'平方米'
  57. dict["详细标题"]=title[0]
  58. dict['名称']=map[0]
  59. dict["具体位置"]=local[1]
  60. dict['房间结构']=fanpa1(fangjian1,data)+'室'+fanpa1(fangjian2,data)+'厅'
  61. if len(zhuangxiu)==3:
  62. dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]+','+zhuangxiu[2]
  63. elif len(zhuangxiu)==2:
  64. dict["装修情况"]=zhuangxiu[0]+','+zhuangxiu[1]
  65. else:
  66. dict["装修情况"] = zhuangxiu[0]
  67. list1.append(dict)
  68. return list1
  69. def save(list):
  70. filename = "C:/Users/孟尚宇/Desktop/安居客二十页.xls"
  71. book = xlwt.Workbook()
  72. sheet1=book.add_sheet("sheet1")
  73. header = ['价格','面积','详细标题','名称','具体位置','房间大小','装修情况']
  74. for i in range(len(header)):
  75. sheet1.write(0,i,header[i])
  76. j = 1
  77. for i in list:
  78. sheet1.write(j,0,i['价格'])
  79. sheet1.write(j,1,i['面积'])
  80. sheet1.write(j,2,i['详细标题'])
  81. sheet1.write(j,3,i['名称'])
  82. sheet1.write(j,4,i['具体位置'])
  83. sheet1.write(j,5,i['房间大小'])
  84. sheet1.write(j,6,i['装修情况'])
  85. j = j+1
  86. book.save(filename)
  87. print("写入成功")
  88. if __name__ == '__main__':
  89. headers = {
  90. "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",
  91. "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.zu.anjuke.com%2Ffangyuan%2Fp2%2F%3Ffrom_price%3D0%26to_price%3D2500an%7Chttps%3A%2F%2Fcallback.58.com%2F; wmda_session_id_6289197098934=1607426591062-bdd0135e-4c1f-a60c; xzfzqtoken=lbhfULbvUI2tmDmR%2By8o2XgL%2FoD%2Fi8pTDHftNbKQZZ3J9dDc2%2BiE91mVlKbcur5Hin35brBb%2F%2FeSODvMgkQULA%3D%3D",
  92. "path":"/fangyuan/p2/?from_price=0&to_price=2500an"
  93. }
  94. dict2 = []
  95. dict1 = []
  96. for i in range(20):
  97. url = "https://hai.zu.anjuke.com/fangyuan/p{}/".format(i+1)
  98. resopnse=requests.get(url=url,headers=headers).content.decode('utf-8')
  99. list=lxmldata(resopnse)
  100. dict1.append(list)
  101. print("第"+str(i)+"页数据完成")
  102. for j in dict1:
  103. for k in j:
  104. dict2.append(k)
  105. save(dict2)

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

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

第一步导入数据

  1. import numpy as np
  2. import pandas as pd
  3. import matplotlib.pyplot as plt
  4. data2=pd.read_excel(r"C:\Users\xxx\Desktop\安居客二十页.xls")

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

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

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

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

第四步 挑选出有电梯的房子
定义一个函数如果有电梯在’房屋结构’这一字段数据中,则返回True
之后用布尔索引挑选出数据

  1. def home(s):
  2. if '有电梯' in s:
  3. return True
  4. else:
  5. return False
  6. data2['房屋结构']=data2['房屋结构'].map(home)
  7. data2=data2[data2['房屋结构']==1]

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

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

第六步对价格进行分类
对价格分类 500-1000 1000-2000 2000-3000 3000 -4000 4000+

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

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

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

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

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

    想要获取更多Python学习资料可以加

    QQ:2955637827私聊
    或加Q630390733
    大家一起来学习讨论吧!

python爬虫爬取安居客并进行简单数据分析的更多相关文章

  1. Python开发爬虫之BeautifulSoup解析网页篇:爬取安居客网站上北京二手房数据

    目标:爬取安居客网站上前10页北京二手房的数据,包括二手房源的名称.价格.几室几厅.大小.建造年份.联系人.地址.标签等. 网址为:https://beijing.anjuke.com/sale/ B ...

  2. 用Python爬虫爬取广州大学教务系统的成绩(内网访问)

    用Python爬虫爬取广州大学教务系统的成绩(内网访问) 在进行爬取前,首先要了解: 1.什么是CSS选择器? 每一条css样式定义由两部分组成,形式如下: [code] 选择器{样式} [/code ...

  3. python爬虫爬取内容中,-xa0,-u3000的含义

    python爬虫爬取内容中,-xa0,-u3000的含义 - CSDN博客 https://blog.csdn.net/aiwuzhi12/article/details/54866310

  4. python爬虫—爬取英文名以及正则表达式的介绍

    python爬虫—爬取英文名以及正则表达式的介绍 爬取英文名: 一.  爬虫模块详细设计 (1)整体思路 对于本次爬取英文名数据的爬虫实现,我的思路是先将A-Z所有英文名的连接爬取出来,保存在一个cs ...

  5. Python爬虫 - 爬取百度html代码前200行

    Python爬虫 - 爬取百度html代码前200行 - 改进版,  增加了对字符串的.strip()处理 源代码如下: # 改进版, 增加了 .strip()方法的使用 # coding=utf-8 ...

  6. 使用Python爬虫爬取网络美女图片

    代码地址如下:http://www.demodashi.com/demo/13500.html 准备工作 安装python3.6 略 安装requests库(用于请求静态页面) pip install ...

  7. Python爬虫|爬取喜马拉雅音频

    "GOOD Python爬虫|爬取喜马拉雅音频 喜马拉雅是知名的专业的音频分享平台,用户规模突破4.8亿,汇集了有声小说,有声读物,儿童睡前故事,相声小品等数亿条音频,成为国内发展最快.规模 ...

  8. Python爬虫爬取全书网小说,程序源码+程序详细分析

    Python爬虫爬取全书网小说教程 第一步:打开谷歌浏览器,搜索全书网,然后再点击你想下载的小说,进入图一页面后点击F12选择Network,如果没有内容按F5刷新一下 点击Network之后出现如下 ...

  9. 一个简单的python爬虫,爬取知乎

    一个简单的python爬虫,爬取知乎 主要实现 爬取一个收藏夹 里 所有问题答案下的 图片 文字信息暂未收录,可自行实现,比图片更简单 具体代码里有详细注释,请自行阅读 项目源码: # -*- cod ...

随机推荐

  1. 【ubuntu】搭建mysql5.7

    一.安装mysql (一) 安装mysql 注意别安装8,8配置太高了 $: sudo apt-get install mysql-server or $: sudo apt-get install ...

  2. Linux中配置环境变量

    Linux中环境变量的搭建(推荐用法) 第一步:进入到/etc/profile.d文件夹下 cd /etc/profile.d 第二步:创建并编辑一个my_env.sh文件 vim my_env.sh ...

  3. nginx介绍及常用功能

    什么是nginx nginx跟Apache一样,是一个web服务器(网站服务器),通过HTTP协议提供各种网络服务. Apache:重量级的,不支持高并发的服务器.在Apache上运行数以万计的并发访 ...

  4. NOIP2012 解题报告

    TG Day1 T3 开车旅行 1. 预处理出从每座城市两人分别会到达的两座城市. 用 set 可以轻松实现. 2. 用倍增优化 DP 令 \(f_{i,j,k}\) 表示从城市 \(j\) 出发,行 ...

  5. T147403 「TOC Round 4」吃,都可以吃

    若不考虑 \(m\) 的限制,打表可以发现: 当 \(p=2^n\left(n>1\right)\) 时,最大的 \(f_i\) 是 \(5\),有十个 \(i\) 的 \(f_i\) 是 \( ...

  6. dubbo协议之编码请求对象体

    上节我们看了如何编码请求头,这节一起看下过程中,对请求对象的编码,涉及对接口,方法,方法参数类型,方法参数进行编码,DubboCodec中重写了这个方法: request.getData向下转型成Rp ...

  7. Bootstrap Blazor 组件介绍 Table (二)自定义模板列功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  8. Spring Boot系列:七、 实现Mybatis多数据源切换

    一.引入相关maven配置 mybatis;  mysql驱动:jdbc <dependency> <groupId>org.mybatis.spring.boot</g ...

  9. 20200509_设置笔记本使用有线访问外网同时wifi访问外网

    1. 控制面板\所有控制面板项\网络连接 2. wifi的使用的手机热点, dhcp分配的, 不用做配置 3. 笔记本获取到的内网静态地址是192.168.3.11, 网关是192.168.3.254 ...

  10. day4(JWT安装配置)

    1.JWT安装配置  1.1安装JWT pip install djangorestframework-jwt==1.11.0 1.2 syl/settings.py配置jwt载荷中的有效期设 # j ...