8.4 系统设置
在开发一个大型应用程序时,需要模块化开发经常用到的系统设置模块。在本节的内容中,将详细讲解实现本项目系统设置模块的过程。
8.4.1 选择版本
因为在当前市面中同时存在Python 2和Python3版本,所以本系统分别推出了对应的两个实现版本。编写文件version.py共用户选择使用不同的Python版本,具体实现代码如下所示。
import sys
if sys.version_info < (3, 0): # 如果小于Python3
PYTHON_3 = False
else:
PYTHON_3 = True
if not PYTHON_3: # 如果小于Python3
reload(sys)
sys.setdefaultencoding("utf-8")
8.4.2 保存日志信息
为了便于系统维护,编写文件log.py保存使用本系统的日志信息,具体实现代码如下所示。
import logging
from lib.utility.path import LOG_PATH
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler(LOG_PATH + "/log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
if __name__ == '__main__':
pass
8.4.3 设置创建的文件名
本系统能够将抓取的房价信息保存到本地CSV文件中,保存CSV文件的文件夹的命名机制有日期、城市和房源类型等。编写系统设置文件path.py,功能是根据不同的机制创建对应的文件夹来保存CSV文件。文件path.py的具体实现代码如下所示。
def get_root_path():
file_path = os.path.abspath(inspect.getfile(sys.modules[__name__]))
parent_path = os.path.dirname(file_path)
lib_path = os.path.dirname(parent_path)
root_path = os.path.dirname(lib_path)
return root_path
def create_data_path():
root_path = get_root_path()
data_path = root_path + "/data"
if not os.path.exists(data_path):
os.makedirs(data_path)
return data_path
def create_site_path(site):
data_path = create_data_path()
site_path = data_path + "/" + site
if not os.path.exists(site_path):
os.makedirs(site_path)
return site_path
def create_city_path(site, city):
site_path = create_site_path(site)
city_path = site_path + "/" + city
if not os.path.exists(city_path):
os.makedirs(city_path)
return city_path
def create_date_path(site, city, date):
city_path = create_city_path(site, city)
date_path = city_path + "/" + date
if not os.path.exists(date_path):
os.makedirs(date_path)
return date_path
# const for path
ROOT_PATH = get_root_path()
DATA_PATH = ROOT_PATH + "/data"
SAMPLE_PATH = ROOT_PATH + "/sample"
LOG_PATH = ROOT_PATH + "/log"
if __name__ == "__main__":
create_date_path("lianjia", "sh", "20160912")
create_date_path("anjuke", "bj", "20160912")
8.4.4 设置抓取城市
本系统能够将抓取国内主流一线、二线城市的房价,编写文件city.py设置要抓取的城市,实现城市缩写和城市名的映射。如果想抓取其他已有城市的话,需要把相关城市信息放入到文件city.py中的字典中。文件city.py的具体实现代码如下所示。
cities = {
'bj': '北京',
'cd': '成都',
'cq': '重庆',
'cs': '长沙',
'dg': '东莞',
'dl': '大连',
'fs': '佛山',
'gz': '广州',
'hz': '杭州',
'hf': '合肥',
'jn': '济南',
'nj': '南京',
'qd': '青岛',
'sh': '上海',
'sz': '深圳',
'su': '苏州',
'sy': '沈阳',
'tj': '天津',
'wh': '武汉',
'xm': '厦门',
'yt': '烟台',
}
lianjia_cities = cities
beike_cities = cities
def create_prompt_text():
"""
根据已有城市中英文对照表拼接选择提示信息
:return: 拼接好的字串
"""
city_info = list()
count = 0
for en_name, ch_name in cities.items():
count += 1
city_info.append(en_name)
city_info.append(": ")
city_info.append(ch_name)
if count % 4 == 0:
city_info.append("\n")
else:
city_info.append(", ")
return 'Which city do you want to crawl?\n' + ''.join(city_info)
def get_chinese_city(en):
"""
拼音拼音名转中文城市名
:param en: 拼音
:return: 中文
"""
return cities.get(en, None)
def get_city():
city = None
# 允许用户通过命令直接指定
if len(sys.argv) < 2:
print("Wait for your choice.")
# 让用户选择爬取哪个城市的二手房小区价格数据
prompt = create_prompt_text()
# 判断Python版本
if not PYTHON_3: # 如果小于Python3
city = raw_input(prompt)
else:
city = input(prompt)
elif len(sys.argv) == 2:
city = str(sys.argv[1])
print("City is: {0}".format(city))
else:
print("At most accept one parameter.")
exit(1)
chinese_city = get_chinese_city(city)
if chinese_city is not None:
message = 'OK, start to crawl ' + get_chinese_city(city)
print(message)
logger.info(message)
else:
print("No such city, please check your input.")
exit(1)
return city
if __name__ == '__main__':
print(get_chinese_city("sh"))
8.4.5 处理区县信息
因为每个城市都有不同的行政区,所以编写文件area.py处理区县信息,具体实现代码如下所示。
chinese_city_district_dict = dict() # 城市代码和中文名映射
chinese_area_dict = dict() # 版块代码和中文名映射
area_dict = dict()
def get_chinese_district(en):
"""
拼音区县名转中文区县名
:param en: 英文
:return: 中文
"""
return chinese_city_district_dict.get(en, None)
def get_districts(city):
"""
获取各城市的区县中英文对照信息
:param city: 城市
:return: 英文区县名列表
"""
url = 'https://{0}.{1}.com/xiaoqu/'.format(city, SPIDER_NAME)
headers = create_headers()
response = requests.get(url, timeout=10, headers=headers)
html = response.content
root = etree.HTML(html)
elements = root.xpath(CITY_DISTRICT_XPATH)
en_names = list()
ch_names = list()
for element in elements:
link = element.attrib['href']
en_names.append(link.split('/')[-2])
ch_names.append(element.text)
# 打印区县英文和中文名列表
for index, name in enumerate(en_names):
chinese_city_district_dict[name] = ch_names[index]
# print(name + ' -> ' + ch_names[index])
return en_names