爬虫是我在数据分析学习道路上的一个起点,同时也是我的兴趣点,当你通过自己的代码从各种网站上爬取到你想要的数据时,那种自豪感油然而生,虽然这可能不值一提,但对于不太精于代码的我们却有着非凡的意义。因为当我们在学习遇到困难,感到无助时,而你能通过自己的努力去克服这些困难,当你看到一行行的数据在下载时,所有的疲惫都消失了,那种又充满力量的感觉很好。
身在厦门的我们,房价就是我们一直在讨论的问题,今天就对安居客房产网发布的数据进行下载分析,由于新房数据不多,本次以二手房数据为主。
环境:python3.6、pycharm2017、mysql。
目标:抓取厦门安居客发布的二手房信息,如下图,包含所属区域、房源连接、房源id、标题、房屋编码+发布时间、小区名称、户型、单价、面积、首付、建筑年代、住宅属性、楼层、装修程度、产权年限以及备注信息。从图上可以看到结构还是相对工整简单。厦门二手房房产网,厦门二手房交易信息,厦门二手房出售 - 58安居客
明确目标后,下面就直接进入项目。
一、项目需要导入的包如下:
import requests,re
import urllib.request
from bs4 import BeautifulSoup
from lxml import etree
import pymysql
import time
from urllib import request
import random,ssl
二、本项目最终是将数据下载至数据库,我使用的是mysql,数据库连接如下:
print('连接到mysql服务器...')
db = pymysql.connect(host='localhost',
port=3306,
user='root',
passwd='', #写上自己的数据库密码
db='', #所在的数据库
charset='utf8mb4') #可以插入4字节的非字符串类型*****
print('连接上了!')
cursor = db.cursor()
cursor.execute("DROP TABLE IF EXISTS ajkfdc_esf_20190225") #表名使用 来源-分类-日期的形式
print('删除已经存在的表')
sql = '''create table ajkfdc_esf_20190225(
housepage varchar(5) default null ,
housenum varchar(10) default null ,
region varchar(20) default null ,
Hyperlink varchar(500) default null,
housid varchar(30) default null ,
title varchar(800) default null,
houseencode varchar(50) default null,
community varchar(100) default null,
Apartment varchar(255) default null,
unitprice varchar(100) default null,
area varchar(30) default null,
paymentsfirst varchar(20) default null,
madeyear varchar(10) default null,
tpyehous varchar(20) default null,
floor varchar(30) default null,
Renovation varchar(30) default null,
uesyear varchar(10) default null,
usedyear varchar(10) default null,
note varchar(1000) default null
)'''
cursor.execute(sql)
# 网页的请求头
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
}
housepage = 1
housenum = 0
三、通过对主页的一个分析,可以看到每一页有固定的房源信息,然后指向下一页
主函数如下:
def get_page(url): #在调用函数时,传入一个区的主页连接
global housepage
response = requests.get(url, headers=header)
#通过BeautifulSoup进行解析出每个房源详细列表并进行打印
soup_idex = BeautifulSoup(response.text, 'html.parser')
result_li = soup_idex.find_all('li', {'class': 'list-item'})
# 进行循环遍历其中的房源详细列表
for i in result_li:
page_url = str(i)
soup = BeautifulSoup(page_url, 'html.parser')
# 由于通过class解析的为一个列表,所以只需要第一个参数
result_href = soup.find_all('a', {'class': 'houseListTitle'})[0]
# 获取到具体房源的连接后,调用详细信息页面的函数
get_page_detail(result_href.attrs['href'])
# 本页完成后指向下一页
result_next_page = soup_idex.find_all('a', {'class': 'aNxt'})
if len(result_next_page) != 0: #!=连续递归
# 函数进行递归
get_page(result_next_page[0].attrs['href'])
housepage +=1
#pass
else:
print('没有下一页了')
这里先解析主页,可以看到class属性为“list-item”的li就是房源信息,一个li代表一个房源,所以先find_all所有的li标签,插入列表。
接着用for循环进入li,解析li,在li里面查找标题的超链接,经过分析查看第一个a标签就是标题,get_page_detail(result_href.attrs['href']),获取标题的超链接并调用详细页面获取数据的函数,本页所有房源都循环一遍后,判断是否存在下一页,递归循环直至结束。
四、接着对详细页面进行分析,代码如下:
def my_Beautifulsoup(response):
return BeautifulSoup(str(response), 'html.parser')
# 详细页面的爬取
def get_page_detail(url):
global housenum
response = requests.get(url, headers=header)
time.sleep(random.randint(1,3))
if response.status_code == 200: #请求成功
housenum += 1
soup = BeautifulSoup(response.text, 'html.parser')
# 地区、链接、id、标题等基本信息
region_div = soup.find_all('div', {'class': 'p_1180 p_crumbs'})
soup_1 = my_Beautifulsoup(region_div)
#region = soup_1.find_all('a')[2].get_text() #获取地区--------------
Hyperlink = url #房源链接-------------
print(Hyperlink)
housid = url[32:43] #房源id---------------
title = soup.find_all('h3', {'class': 'long-title'})[0].get_text() #房源title------------
#房源基本信息
#housecode = soup.find_all('span', {'id': 'houseCode'})[0].get_text()
#housecode = re.findall(r"d+.?d*", housecode)
houseencode = soup.find_all('span', {'class': 'house-encode'})[0].get_text() #房屋编码、发布时间---------
community = soup.find_all('a', {'_soj': 'propview'})[0].get_text() #所属小区-------------------
Apartment = soup.find_all('div', {'class': 'houseInfo-content'})[1].get_text()
Apartment = Apartment.replace("n", "") #户型---------------------
unitprice = soup.find_all('div', {'class': 'houseInfo-content'})[2].get_text() #单价--------------------
area = soup.find_all('div', {'class': 'houseInfo-content'})[4].get_text() #面积-------------------
paymentsfirst = soup.find_all('div', {'class': 'houseInfo-content'})[5].get_text()
paymentsfirst = paymentsfirst.strip() #参考首付------------
madeyear = soup.find_all('div', {'class': 'houseInfo-content'})[6].get_text()
madeyear = madeyear.strip() #建造年代-----------
tpyehous = soup.find_all('div', {'class': 'houseInfo-content'})[9].get_text() #房屋类型-------
floor = soup.find_all('div', {'class': 'houseInfo-content'})[10].get_text() #所在楼层---------
Renovation = soup.find_all('div', {'class': 'houseInfo-content'})[11].get_text() #装修---------
uesyear = soup.find_all('div', {'class': 'houseInfo-content'})[12].get_text() # 装修---------
usedyear = soup.find_all('div', {'class': 'houseInfo-content'})[14].get_text() # 装修---------
housinfo_div = soup.find_all('div', {'class': 'houseInfo-item'})
note_span = my_Beautifulsoup(housinfo_div)
#print(note_span)
note = note_span.find_all('span')[1].get_text() #房屋说明-----
region_div_2 = soup.find_all('div', {'class': 'houseInfo-content'})[3]
region_div_a = my_Beautifulsoup(region_div_2)
region = region_div_a.find_all('a')[0].get_text() # 地区--------------------
print(region, housid, title, houseencode,note)
#print(region, Hyperlink, housid, title, houseencode, community, Apartment, unitprice, area, paymentsfirst,madeyear,tpyehous,floor,Renovation,uesyear,usedyear)
# -------------------------------------------------------------做插入数据库的操作-----------------------------------------------------------------
insert_sql = "insert into ajkfdc_xf_20190225(housepage,housenum,region, Hyperlink, housid, title, houseencode, community, Apartment, unitprice, area, paymentsfirst,madeyear,tpyehous,floor,Renovation,uesyear,usedyear,note) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
insert_data = [housepage,housenum,region, Hyperlink, housid, title, houseencode, community, Apartment, unitprice, area, paymentsfirst,madeyear,tpyehous,floor,Renovation,uesyear,usedyear,note] # 转换后字符串的插入数据
cursor.execute(insert_sql, insert_data)
# print('******完成此条插入!')
db.commit()
1、首先由于频繁使用BeautifulSoup,所以定义了一个my_Beautifulsoup的函数,方便调用。
2、在属性为p_1180 p_crumbs的div里面获取到房源连接;后面的各个属性也是通过对应的class值获取的数据;
3、上面获取到的值都赋值到一个变量,再将各个变量合并成一个列表,再用insert语句插入数据库。
五、接着利用一个mian函数调用前面那个主函数即可。
if __name__ == '__main__':
# url链接
url = 'https://xm.anjuke.com/sale/jimei/' #集美、海沧、翔安 、湖里、同安、 已抓
# 页面爬取函数调用
get_page(url)
通过分析页面网址,其构成情况是 https://xm.anjuke.com/sale/+区域全拼,其实可以通过写出六大区的网址形成列表,再用循环调用的形式自动爬取厦门全区的数据。只是这里所做的爬虫程序没有反爬机制,前面利用sleep控制访问速度,一个区基本需要2-3小时爬完,所以手动更改主页地址,自行分区爬取。
最后爬取效果如下图,水平有限,希望大家指正。