首先指出实验文档中的错误:
第一幅图中的city.py应该为citys.py,另外吐槽一下老师的英文水平,city的复数写成cities是不是会更好些???
体会
学到了很多东西。
严格而言,这并不是一个爬虫,只能说是一个根据用户输入来即时爬取特定页面来返回信息的小程序。其中正则表达式的使用、文件的读取、信息的存储形式都是值得注意的地方。
需要注意的地方
1
with open("citys.csv", "r") as f:
reader = csv.reader(f)
for city in reader:
city_dict[city[0]] = city[1]
注意上面csv.reader的用法。因为我们平时读取文件,一般会写成:
with open('/path/to/file', 'r') as f:
print(f.read())
直接f.read()就可以把文件都出来了,而csv这个东西不是这样操作的。
那么,csv.reader(f)读出来的东西到底是什么类型的呢?通过下面的代码可以得知:
>>> type(city)
>>> type(reader)
reader的类型是——_csv.reader,而对于其中的每一项,即city,其类型为list,故下面可以把每个list取出来,写成dict的格式。
2
在输入下面的代码的时候:
# 打印所有的城市名
for city_name in city_dict.keys():
print city_name,
年少无知的我一度以为文档写错了!
后来才发现,这种写法是print的小技巧,很厉害!
p'r
3
整个流程的逻辑是:首先列举出链家所有的城市让你选一个,当你输入城市名称之后,代码根据城市名称得到城市的url,然后根据城市的url加上ershoufang后缀,得到该城市二手房的url,然后访问该二手房url,提取该页面的所有地区的url,然后让你输入地区从而可以进入地区的页面,找到房屋信息,虽然有点绕,但是还算清晰。
4
在对网址进行组合的时候,要注意观察和总结特征。
如,选择过地区之后,要进入该地区房屋列表的页面,该页面的网址应该是:
house_info_url = city_url + district_url[1:]
5
要多加学习程序化的思考方式,应当设想各种出错的可能性并针对性的设计方案,比如用urllib打开特定页面,如果打不开怎么办?程序不就死了吗,我认为文档中的方法就很好。当然在实际超过过程中,可以选择忽略这个页面,继续进行下面的工作。
if page.getcode() == 200:
html = page.read()
bsobj = BeautifulSoup(html, "html5lib")
return bsobj
else:
print "页面错误"
sys.exit()
6
对于房屋信息的保存方式也很值得学习:
整理每个房源的信息,然后组成一个词典,把很多房源的词典再写入一个列表中。
# 将页面中每一条房屋信息保存为一个字典,将所有的字典保存在列表中,返回列表
def get_house_info_list(url):
house_info_list = []
bsobj = get_bsobj(url)
if not bsobj:
return None
house_list = bsobj.find_all("li", {"class":"clear"})
for house in house_list:
# 标题
title = house.find("div", {"class": "title"}).get_text().encode("utf-8")
# 获取信息数据(例:加怡名城 | 2室1厅 | 62.48平米 | 西 | 精装),通过“|”符号分割字符串
info = house.find("div", {"class": "houseInfo"}).get_text().split("|")
# 小区(例:加怡名城),strip()去除字符串两边的空格,encode,将字符串编码成 utf-8 格式
block = info[0].strip().encode("utf-8")
# 房型(例:2室一厅)
house_type = info[1].strip().encode("utf-8")
# 面积大小,保留整数(例:62.48平米,保留整数后为 62)
size_info = info[2].strip()
size = re.findall(r"\d+", size_info)[0]
# 价格,保留整数(例:120.3万,保留整数后为 120)
price_info = house.find("div", {"class": "totalPrice"}).span.get_text()
price = re.findall(r"\d+", price_info)[0]
# 添加到列表中
house_info_list.append({
"title": title,
"price": int(price),
"size": int(size),
"block": block,
"house_type": house_type
})
return house_info_list
7
注意list的extend用法,该方法用于在列表后面追加另外一个列表。文档中用于在一个房源列表中追加另外两个房源信息表格:
house_info_list = []
# range(3),即前三个子页面
for i in range(3):
new_url = url + 'pg' + str(i+1)
house_info_list.extend(get_house_info_list(new_url))
下面是运行截图
(后面的就不放了,没啥意思)