对于爬取数据,网上有很多零散的教程,正羊羊借最近自己的一个项目,针对广州房价来进行一次爬虫与数据分析。从最开始的数据爬取到之后的数据清洗与分析,正羊羊尽量将各个流程给大家讲清楚。本篇讲的是如何爬取数据并把数据保存到csv文件中。
温馨提示
建议在公众号“正羊羊部落”后台回复“房价”获取代码,在电脑上打开来对着看。另外,本程序尚未做效率优化处理,不要直接运行,建议在第79行代码的列表中只留下天河区,或者是在第86行代码中缩小爬取的页数范围再进行爬取。对本代码的进一步优化请看后续文章。
本篇文章的架构如下:
这个项目的目的是爬取某(lianjia)网中关于广州二手房的信息,包括房子的名称、特点、售价、位置等等。房子的位置范围是按照网站上区域的分类,包括天河、越秀、荔湾、海珠、番禺、白云、黄埔、从化、增城、花都、南沙这11个区,相应地,程序会生成11个csv文件,分别是各个地区的房价信息。
这个爬取数据的模块只需要几个常见的第三方库:
requests:访问网站,获取含所需数据的html文件
bs4(BeautifulSoup): 解析html文件,获取所需数据的文本
csv:将数据导入到csv文件中
time:控制网站的访问频率
random:配合time库设定频率
re:用正则表达式定位文本信息
获取html
网站(url)格式:https://gz.lianjia.com/ershoufang/{}/pg{}/,两个花括号分别为地区和页数,在程序中要设定候选的参量,比如,对于天河区网页的第一页,两个花括号分别替换成tianhe和1,即https://gz.lianjia.com/ershoufang/tianhe/pg1/。
整个爬取流程中,页数为100页,用列表来装着那11个地区的简拼:
将html.text用print函数打印结果如下:(只展示部分)
解析html
得到html.text后,就可以用BeautifulSoup来对其解析了。解析的意思就是从这些文本里提取出我们需要的信息。读者可以去看看文本中间部分的中文,那些就是我们要的信息:
为了方便,我们将BeautifulSoup简写成BS。BS给我们提供了CSS选择器,这个选择器的作用就是选取信息。我们在网页上把鼠标放在随便一个房子的名称上,右键点击“检查”或“审查元素”:
这样就可以打开监控台了,而且它还会将鼠标位置对应的信息定位到相应的代码上:
然后我们将鼠标放在上图的蓝色代码上,右键选择Copy目录下的“Copy selector”:
这样我们就把定位这个房名的css选择器的指引代码给复制了下来,在文本框中粘贴一下就可以看到了:
这个和代码第25行的字符串内容是不是很像,唯一不一样的就是li节点,我们copy下来的多了“:nth-child(1)”部分,这是因为,我们copy下来的,对应的是第一个房子的房名,而在程序里确实要这一整页的房名,所以,把这部分删掉就可以了。
通过.select语法,我们就可以利用经处理后copy下来的代码来选取信息了:
这几行依先后分别对应下图的这几处位置的信息:
另外,在这一部分还外加了简单的异常处理,try和except。如果其中某一个解析出现问题,程序会直接输出“failed!”的语句。
这部分程序最终会输出该网页各房在上图6个相应位置的节点信息。按照上图,程序里Titles、TotalPrice、UnitPrice、HouseInfo、buildings、attention分别得到如下文本:(这6个变量均为列表,包含该页每个房子相应位置的信息)
提取信息点
为了后续数据处理的方便以及信息本身的实用性,我们还需要对这些文本进行拆解,提取出最精炼的信息,而这也就是代码第37行到第71行的任务。虽然内容有点多,但是每一条信息的解析原理是相似甚至是一样的。
以房子的总价为例:
Tp是TotalPrice这个列表的某一个元素,代表着该网页中某一个房子的总价信息,用.get_text()方法来获取该信息的字符串格式,选择数字,去掉“万”字,这便于数据分析。去掉“万”字的方法是字符串特定序列的截取,字符串由前到后标号是0,1,2,...,而由后往前则是-1,-2,-3,...,代码中用[:-1]索引表示从字符串的倒数第2个字符一直往前,直到最前端。Strip()函数的作用很简单,只是为了去除字符串首尾的空格而已。
在解析HouseInfo这部分的文本时,我们可以看到网页上是用“|”符号将各个信息点划分开的,所以我们就用split()函数,按照“|”符号,将这条信息切割。
最终形成由各信息点组成的列表,每个位置的信息列表最终都会组合到results变量中,供下一步的数据存储。
数据存储
程序的第80行到第90行的任务就是数据存储,针对每一个地区(for p in place),都会打开一个相应的csv文件:
天河区的csv文件的内容示例如下:
我们可以看到,每一列的第一个元素是这一列的列名(看上图红框),而程序的第82行至84行就是设定这个列名,其中的函数均来自csv这个第三方库。
红色框中的两个循环头,就是依次表示了遍历每一个地区、每一页;而黄色框中的循环头,就是表示遍历爬取当前页的每一个房子的信息。因为results是包含该页的所有房子的信息,而我们可以看到。在上上图的csv文件截图中,每一行表示一个房子的信息,也就是说,程序每次会从results中取出一个房子的信息,再通过writerow(item)函数,把每个房子的信息写入csv文件中。
设置访问频率
最后,用time库和random库来设置爬取频率。
Time.sleep()表示程序到这里会停止一段时间,时间的长短由括号内的数值决定,这个数值由random库从0到3中随机生成一个值,也就是说,程序到这里可能会停顿0、1、2、3秒中的某一种可能。
在爬取数据的过程中,我们可以看到如下的进度示例:
最终的数据文件: