requests和selenium获取住宅信息

10 篇文章 0 订阅
2 篇文章 1 订阅

初学爬虫,写了一个获取soufun住宅信息的方法。

大致分为三步:

1、获取每个区的小区列表信息

2、获取每个小区的建筑面积、房屋户数等信息

3、处理每个区的住宅信息

一、selenium获取小区列表

首先查看soufun的网页信息,小区列表见https://wuhan.esf.fang.com/housing/,可以看到总共有7000+小区如果直接翻页最多只能翻100页,要获取全部的小区列表,需要先按区进行过滤,然后再翻页,逐页获取小区列表。

browser.find_elements_by_css_selector("div[class = 'qxName']>a")  #通过CSS选择器获取每个区域的的链接TAG

totalpage = browser.find_element_by_class_name('txt')  #总页数TAG

currentpage = browser.find_element_by_class_name("pageNow")  #当前页TAG

nextpagebutton = browser.find_element_by_id("PageControl1_hlk_next") #下一页TAG

celllist = bs4.select("div[class = 'houseList']>div")  #获取每一页的小区列表,在houseList下面分为多个DIV

for cell in celllist:
      name = cell.select("a[class = 'plotTit']")[0].get_text()  #获取小区名称
      
      link = cell.select("a[class = 'plotTit']")[0].get("href") #获取小区链接 
     
      locationlist = cell.select("dd>p:nth-child(2)>a")   

      locationlist[0].get_text()  #小区所在区域

      locationlist[1].get_text()  #小区所在街道

 

二、request获取小区列表

根据第一步获取的小区链接,获取每个小区的详细信息,详细信息需要在链接基础上加/xiangqing/如:

https://wankehongjun.fang.com/xiangqing/

bs4.select("div[class = 'inforwrap clearfix']>dl>dd")

 

三、pandas处理获取的数据

1、数据显示

在print查看数据时,经常显示不全,查了一下需要set_option设置显示格式。

pandas.set_option('expand_frame_repr', False)  显示DataFrame是否可以换行True就是可以换行显示。设置成False的时候不允许换行

pandas.set_option('display.max_rows',20) #显示最大行数,超过的行中间为省略号,None表示显示所有的行。

pandas.set_option('display.max_columns', 20) #显示最大列数,超过的列中间为省略号,None表示显示所有的列。

pandas.set_option('display.width', 400) #显示最大宽度,超过就会换行。

2、格式转换

在pandas打开excel文件,打开文件的数据格式是自行判断的,特别对于数据列,如果有一个数据为str则会转换为Object类型,后续计算将无法进行。

所以先要处理异常的数据,也就是常说的数据清洗,然后将格式转换过来。

数据处理参考下面的博文。只有数据清洗之后,且转换为float64或者int64才能正常进行数据处理。

https://www.cnblogs.com/onemorepoint/p/9404753.html

 

 

 

filedata = pandas.read_excel(filename)

filedata.info()

housedata = filedata[filedata['类型'] == '住宅']  #过滤需要处理的数据,只处理类型为住宅的行。

col_to_convert = ["建筑面积","容积率","物业费"]   #读取的时候只要有异常数据,就读为了object类型,定义需要转换为numeric的列,逐列转换为numeric,对于异常数据转换为NAN
for col in col_to_convert:
    filter_data1.loc[:,col] = pandas.to_numeric(filter_data1.loc[:,col],errors='coerce')

 

最后通过pivot_table得到数据,建筑面积总共6亿平方米,套数326万。房屋总数和建筑面积对不上,后来看了一下统计数据,住宅总共有5592条数据,其中3267条有建筑面积,4908条有房屋总数,有一部分建筑面积填的异常大导致数据异常。房屋总数较为可信。

 0   类型      5592 non-null   object 
 1   区域      5592 non-null   object 
 7   建筑面积    3267 non-null   float64
 8   房屋总数    4908 non-null   float64

 

 建筑面积房屋总数
东湖高新区48174909287740
东西湖68552783251768
新洲1630400059994
武昌69827404546951
武汉周边1431306911755
汉南961061013027
汉阳55583398286434
江夏30744369153415
江岸57829587408917
江汉26974541259508
沌口19425930110050
洪山63125071229349
硚口23333837207941
蔡甸2130238288748
青山21726329176268
黄陂31805281168196
总计5786335003260061

 

在绘制柱状图时,想同时显示具体数值,根据下面文档查看了下没有绘制的接口。在网上找了下,需要pyplot.text一个数一个数的绘在图上。

for xnum, ynum in zip( range(0,16), house['建筑面积']):
    pyplot.text(x=xnum-0.03, y= ynum+0.01, s=ynum,ha='center', va= 'bottom',fontsize=11)

https://blog.csdn.net/brucewong0516/article/details/80524442

 

四、异常处理

1、openxl保存数据时异常

openpyxl.utils.exceptions.IllegalCharacterError

根据https://blog.csdn.net/javajiawei/article/details/97147219介绍是openxl检测cell时如果字符非法会抛出异常。

这里面的非法字符都是八进制,可以到对应的ASCII表中查看,都是不常见的不可显示字符,例如退格,响铃等,在此处被定义为excel中的非法字符。

ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')

解决上述错误有两种方法

1,既然检测到excel中存在[\000-\010]|[\013-\014]|[\016-\037]这些非法的字符,因此可以将字符串中的非法字符替换掉即可,在重新写入excel即可。如下:

text= ILLEGAL_CHARACTERS_RE.sub(r'', text)

2,使用xlsxwriter

import xlsxwriter
outputData.to_excel(outputExcelFilePath, engine='xlsxwriter')


outputData是一个DataFrame,在 xlsxwriter应该也是替换掉非法字符,省去了我们手工操作。

2、class定位

当一个TAG有多个class属性时,如下DIV有"main current clearfix"三个class,如果用selenium的find_element_by_class_name方法查找,只能选择其中的一个class定位,还有一种方法是通过selenium的CSS定位find_element_by_css_selector可以成功。

如果使用英文点替换,则可以正常定位   find_element_by_class_name("main.current") ,这种方法没有试过。

类似的,在BeautifulSoup中,通过CSS选择器定位如果选择所有的class可以查找成功,如果选择其中一个class属性会查找失败

 <div class="main current clearfix">



Selenium:

find_element_by_class_name("main current clearfix") #失败

find_element_by_class_name("clearfix")  #成功

find_element_by_css_selector("div[class='main current clearfix']")  #成功



BeautifulSoup:

select("div[class='main current clearfix']")  #成功

select("div[class='clearfix']")  #失败


 

3、解析乱码问题

通过requests获取网页信息,然后通过BeautifulSoup解码后获取的信息为乱码,查找到了一篇文章介绍requests和BeautifulSoup编解码方法。

https://www.jianshu.com/p/69401b84419e

requests会自动将从服务器端获取到的内容自动转换成unicode, 而beauifulsoup也会将获取到内容自动解码成unicode。既然response.text已经是unicode形式,那么再传递给beautifulsoup,是unicode->unicode之间的直接传递,应该不存在编码转换错误的情况,那么为什么最后print出来的会是乱码呢?

requests和beautifulsoup都会自行猜测原文的编码方式,然后用猜测出来的编码方式进行解码转换成unicode。大多数时候猜测出来的编码都是正确的,但也有猜错的情况,如果猜错了可以指定原文的编码。

1、requests解码

response.text返回的类型是str

response.content返回的类型是bytes,可以通过decode()方法将bytes类型转为str类型

传递给Beautiful Soup的时候两种方法都可以,content需要通过response.content.decode()的方式获取相应的html页面

  • response.text 
    解码类型:根据HTTP头部对响应的编码做出有根据的推测,推测的文本编码 
    如何修改编码方式:response.encoding = 'gbk'
  • response.content 
    解码类型:没有指定 
    如何修改编码方式:response.content.decode('utf8')

requests的编码格式通过print(response.encoding)查询,可以通过response.encoding = 'XXX'指定编码格式。

2、Beautiful Soup解码

任何HTML或XML文档都有自己的编码方式,比如ASCII 或 UTF-8,但是使用Beautiful Soup解析后,文档都被转换成了Unicode,Beautiful Soup用了 编码自动检测 子库来识别当前文档编码并转换成Unicode编码. BeautifulSoup 对象的 .original_encoding 属性记录了自动识别编码的结果,可以通过传入 from_encoding 参数来指定编码方式:

soup.original_encoding  #查询解码格式

soup = BeautifulSoup(markup, from_encoding="iso-8859-8")  #指定解码格式

通过Beautiful Soup输出文档时,不管输入文档是什么编码方式,输出编码均为UTF-8编码。

如果不想用UTF-8编码输出,可以将编码方式传入 prettify() 方法,注意charset字段已经根据设置改为了latin-1。

print(soup.prettify("latin-1"))
# <html>
#  <head>
#   <meta content="text/html; charset=latin-1" http-equiv="Content-type" />
# ...

还可以调用 BeautifulSoup 对象或任意节点的 encode() 方法,就像Python的字符串调用 encode() 方法一样。

encoding是从http中的header中的charset字段中提取的编码方式,若header中没有charset字段则默认为ISO-8859-1编码模式,则无法解析中文,这是乱码的原因

apparent_encoding会从网页的内容中分析网页编码的方式,所以apparent_encoding比encoding更加准确。当网页出现乱码时可以把apparent_encoding的编码格式赋值给encoding。

response = requests.get(link, chromehead)
response.encoding = response.apparent_encoding
bs4 = BeautifulSoup(response.text, 'html.parser')

 

4、pyplot绘图乱码

pyplot在绘制图片时如果有中文时只会显示一个方框,产生中文乱码的原因就是字体的默认设置中并没有中文字体,所以我们只要手动添加中文字体的名称就可以了

在程序开头手动增加如下代码,就可以正常绘制中文。

from pylab import *

mpl.rcParams['font.sans-serif'] = ['SimHei']

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值