最近考虑换个环境,打算去租个房子,但是租房信息那么多,我们能不能把它爬取下来做个统计,看看什么价位的房子最多,哪个地段的房子最便宜呢
在爬取之前,请大家安装下BeautifulSoup库和requests库还有pymysql库
安装方法有两种:
1、cmd中pip install + 库名安装
2、pycharm中File-setting-project-InterPreter,按照下图所示安装就可以了
安装BeautifulSoup如果你是python3,请选择安装BeautifulSoup4
解释下这几个库的作用:
Requests只要是做模拟请求
BeautifulSoup主要是做解析,把requests请求的response根据你指定的规则去解析
Pymysql是保存数据用的,这里我们保存数据使用的是mysql,如果不想保存在mysql中可以不安装这个库,比如保存excel中,需要安装csv库,这里就不多说了
我们这次爬取的网站是安居客,打开网站-点击租房-本地
我们看到一大波房源,
此时的连接
https://jn.zu.anjuke.com/?from=navigation
点击下一页
https://jn.zu.anjuke.com/fangyuan/p2/
再下一页
https://jn.zu.anjuke.com/fangyuan/p3/
发现规律了没,第几页就是P几对不对
那第一页呢,我们试试p1,
https://jn.zu.anjuke.com/fangyuan/p1/
发现这个url和https://jn.zu.anjuke.com/?from=navigation是同一个页面
所以我们要拼接的url现在已经很明确了,只需要使用for循环就可以啦,看代码
from bs4 import BeautifulSoup import requests import pymysql.cursors class Spilser: base_url = "https://jn.zu.anjuke.com/fangyuan/p" def getRoom(self): for i in range(1,50): url = self.base_url+str(i)+"/" print("访问的url"+url) spider = Spilser() spider.getRoom()
前3行就不用说了吧,就是导入下我们安装的类库
第5行,我们声明了一个爬虫的类,然后一个base_url成员变量,一个getRoom方法,在里面for循环,输出1到50页房源的url,这里可以打印下,看看url是否正确
是不是炒鸡简单?
我们继续
拿到每一页的链接之后怎么做?当然是请求这些链接啦,我们使用requests来请求,看代码
from bs4 import BeautifulSoup import requests import pymysql.cursors class Spilser: base_url = https://jn.zu.anjuke.com/fangyuan/p headers = { 'Connection': 'keep-alive', 'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9' } def getRoom(self): for i in range(1,50): url = self.base_url+str(i)+"/" print("访问的url"+url) response = requests.get(url,headers=self.headers).text rooms = BeautifulSoup(response,'lxml').findAll('div',class_='zu-itemmod')
response就是我们请求后服务器返回给我们的数据(可以理解为我们看到的页面)
这里要划重点!!
请求的时候最好加上头信息,让我们的程序请求更像浏览器发出的。
我们使用chrome的控制台(啥?你不知道控制台怎么看?F12啊)看到每个房源信息都是由一个class=‘zu-itemmod’的div,所以我们使用BeautifulSoup的findAll方法去查找指定的class,我们得到的rooms就是一页中所有的房源信息,可以打印下(调试的时候,可以把for循环调成2页就好了)
这是返回的结果
因为rooms是多个房源信息,所以我们要对它进行遍历,代码如下
for room in rooms: # print(room) # 标题 title = room.find('div',class_='zu-info').find('h3').find('a')['title'] # 房间基本信息 room_info = room.find('p',class_='details-item tag').get_text().strip().split('|') room_num = room_area = room_level = room_owner = '' if len(room_info)==3: room_num = room_info[0] room_area = room_info[1] room_level = room_info[2].split('\ue147')[0] room_owner = room_info[2].split('\ue147')[1] if len(room_info)==4: room_num = room_info[0] room_area = room_info[1] room_level = room_info[2] room_owner = room_info[3] # 出租方式 type = room.find('span',class_='cls-1').get_text() # 朝向 toward = room.find('span',class_='cls-2').get_text() # 价格 price = room.find('div',class_='zu-side').find('p').get_text()
解释下上面的几个函数,
get_text()就是去除标签中的文本信息
find()就是找单个标签,可以加特定的条件,比如class来限制
strip()去掉字符串左右的空格
split()按照指定的字符进行分隔
为什么要判断len(room_info) 呢,因为room_info可能会有缺省,比如不写楼层,长度就是3了,还有可能等于2,这里就不再完善了,这篇博文的重点是教大家如何去请求和解析数据,理解了这两块,问题就不大了
这样我们就拿到了基本的数据,现在要做的就是怎么保存数据到mysql
先定义我们数据库的基本信息
MYSQL_HOSTS = '127.0.0.1' MYSQL_USER = 'root' MYSQL_PASSWORD = '' MYSQL_PORT = '3306' MYSQL_DB = 'room' MYSQL_CHARACTERS = 'utf8' 然后写一个入库的方法 def save_data(self,title,room_num,room_level,room_area,room_owner,type,toward,price): # 获取游标 connect = pymysql.Connect(user=self.MYSQL_USER, password=self.MYSQL_PASSWORD, host=self.MYSQL_HOSTS, database=self.MYSQL_DB,charset=self.MYSQL_CHARACTERS) cur = connect.cursor() sql = "INSERT INTO room (id,title,room_num,room_area,room_level,room_owner,type,toward,price) VALUES ( '%s', '%s', '%s' ,'%s', '%s', '%s', '%s', '%s','%s')" value = ('0', title, room_num, room_area,room_level, room_owner, type,toward,price) cur.execute(sql % value) connect.commit()
这里需要注意的是,如果你把主键id设置成自增的话,一定要把id的value设置成0,而不是null
下面就是我们爬去下来的数据了
接来下就是大家结合图表工具做可视化,这里就不必详述;本次的代码我已经传到github,传送门在此