趁着元旦假期,总算把一直想做但一直没做的爬虫起了个头,上一篇写了爬虫的基础代码,这一篇,就是正儿八经开始抓所有的房子信息了。
先说遇到的坑:
1、按第一篇直接进二手房的链接,只有3000个房源,这已经提过了。
2、房源里是没有房源位于哪个区的信息的,对数据分析而言,等于缺了一个重要信息,完全没法用了。
3、原来的想法是在title这个class里面抓房源ID,但是发现有一些房源,在这里是没有房源ID的,必须另找。
4、在跑的时候有报错,不知道是什么原因,直接暴力用try跳过去了。
5、有很多车位信息,其实我是不需要的,但是也抓进来了。
6、第一篇里CSV文件中“区”显示的是拼命,没有汉字,不直观。
7、每天都要抓的数据,区分文件名的时间和抓取时间需要手工加进去。
以下是代码,对于坑1,2,解决办法就是通过每个区进去,找对应的小区,然后进入小区的具体页面去找房源,这样就能记录房源的“区”信息了。
坑3的解决办法就是直接找了另一个class,代码里有。坑5的解决办法是用了一个if,在房子信息里开头标记为车位的,直接就不记录了
坑6:用字典解决
坑7:用import datetime解决
import requests
from bs4 import BeautifulSoup
import re
import math
import datetime
def get_xiaoqu():
# 先列出各区的拼音
area = {'siming': '思明区', 'jimei': '集美区', 'huli': '湖里区', 'tongan': '同安区', 'xiangan': '翔安区', 'haicang': '海沧区'}
with open(r'c:\lianjia'+str(datetime.date.today())+r'.csv', 'a',encoding='utf-8') as f:
f.write('{},{},{},{},{},{},{},{},{},{},{},{},{},{},\n'.format('区','房源编号', '小区', '商圈', '户型', '面积', '朝向', '户型', '装修', '年代','总价', '单价', '抓取时间','标题'))
for a in area: # 对各区做循环
print(area.get(a))
xiaoqu_url = [] # 放一个空列表,用来放各小区的链接
url1 = 'https://xm.lianjia.com/xiaoqu/'+str(a)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66'
}
html = requests.get(url1,headers=headers).text
soup = BeautifulSoup(html,'html.parser')
# print(soup)
# 由于各区的小区数量是不一样d,链接的页数也就不一样,因此需要抓出所有小区数量,再根据数量倒推页数
numbers = soup.find('h2',{'class':'total fl'}).find('span').text
# print(numbers)
page = math.ceil(int(numbers)/30)+1
# print(page)
for p in range(1,page): # 获取每页的小区信息
url2 = 'https://xm.lianjia.com/xiaoqu/'+str(a)+str('/')+str('pg')+str(p)
# print(url2)
html1 = requests.get(url2, headers=headers).text
soup1 = BeautifulSoup(html1, 'html.parser')
# 所有小区的名字的都在ul-li的标签下
infos = soup1.find('ul',{'class':'listContent'}).find_all('li')
# print(infos)
for info in infos: # 获取单个小区的具体信息
# xiaoqu_name = info.find('div',{'class':'title'}).find('a').get_text()
xiaoquurl = info.find('div', {'class': 'title'}).find('a').get('href')
sell_info = int(info.find('div',{'class':'xiaoquListItemSellCount'}).find('a').find('span').text)
# print(sell_info)
# 有的小区是0套房源,因此可以不用把链接放入list
if sell_info > 0:
# xiaoqu_url.append(xiaoquurl)
xiaoquID = re.sub(r'\D', '', xiaoquurl)
sell_page = math.ceil(int(sell_info)/30)+1
try:
for sp in range(1,sell_page):
# https: // xm.lianjia.com / ershoufang / pg2c3911057850738 /
url3 = r'https://xm.lianjia.com/ershoufang/pg' + str(sp) + 'c' + str(xiaoquID)
# print(url3)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66'
}
html = requests.get(url3, headers=headers).text
soup3 = BeautifulSoup(html, 'html.parser')
# print(soup)
houses = soup3.find('ul', {'class': 'sellListContent'}).find_all('li')
# print(infos)
for house in houses:
# 获取房源ID
# print(url3)
house_id = house.find('div', {'class': 'unitPrice'}).get('data-hid')
# 获取房源标题
name = house.find('div', {'class': 'title'}).find('a').get_text()
# 由于小区名字和小区所属商圈都在class=positionInfo这个切片下面,所以需要先将两个名字放入列表,然后分别提取
weizhi = house.find('div', {'class': 'positionInfo'}).find_all('a')
data_list = []
for z in weizhi:
data_list.append(z.get_text())
xiaoqu = data_list[0]
shangquan = data_list[1]
# 有了小区名和位置,接下来就是看房子的具体信息,同样需要先转为列表然后切片
houseinfo = house.find('div', {'class': 'houseInfo'}).get_text()
houseinfolist = houseinfo.split('|')
roominfo = houseinfolist[0]
# print(roominfo)
if roominfo != '车位 ':
# 面积是浮点数,要用正则表达式提取
mianji = re.findall(r'-?\d+\.?\d*e?-?\d*?', houseinfolist[1])[0]
# print(mianji)
chaoxiang = houseinfolist[2]
zhuangxiu = houseinfolist[3]
louceng = houseinfolist[4]
nian = houseinfolist[5]
# louxing = houseinfolist[6]
# 接下来是总价
totalprice = house.find('div', {'class': 'totalPrice'}).find('span').text
# 接下来是每平单价,用正则表达式提取整数
unitprice = re.sub('\D', '', house.find('div', {'class': 'unitPrice'}).find('span').text)
# 接下来是存入csv
f.write('{},{},{},{},{},{},{},{},{},{},{},{},{},{},\n'.format(area.get(a),house_id,xiaoqu,shangquan,roominfo,mianji,chaoxiang,zhuangxiu,louceng,nian,totalprice,unitprice,datetime.date.today(),name))
except:
break
else:
continue
# return xiaoqu_url
get_xiaoqu()