一、前言
研究房价走势和房源信息。
二、知识准备
1.python相关知识储备
2.对Scrapy框架有基本的了解,知道其运行流程和逻辑
3.Xpath和CSS选择器相关知识(本文只使用Xpath,要使用CSS选择器的同学请自行学习)
三、开始编码
1.新建工程
安装Scrapy过程就略过了,首先在通过命令 scrapy startproject shuofangwang新建工程,使用Pycharm打开可以看到其目录结构如下
这些文件分别是:
scrapy.cfg: 项目的配置文件
shuofangwan/: 该项目的python模块。之后您将在此加入代码。
shuofangwan/items.py: 项目中的item文件.
shuofangwan/pipelines.py: 项目中的pipelines文件.
shuofangwan/settings.py: 项目的设置文件.
shuofangwan/spiders/: 放置spider代码的目录.
2.定义Item
Item 是保存爬取到的数据的容器,class HouseItem定义你要保存的数据。import scrapy
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class HouseItem(scrapy.Item):
HouseName = scrapy.Field() #楼盘名
HousePrice = scrapy.Field() #价格
HouseAddress = scrapy.Field() #区域
HouseDetailAddress = scrapy.Field() #详细地址
House_type = scrapy.Field() #户型
HouseComment = scrapy.Field() #留言条数
3.编写爬虫Spider
创建一个Spider,必须继承 scrapy.Spider 类, 且定义以下三个属性name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。
后续的URL则从初始的URL获取到的数据中提取。
parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response
对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response
data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
如下代码为我Spider主代码模块#!/usr/bin/env python
# coding:utf-8
import scrapy
import HouseItem
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class shuofangwnagSpider(scrapy.Spider):
name = "shuofangwang"
allowed_domains = ["newhouse.cs.fang.com"]
offset = 1
url = "http://newhouse.cs.fang.com/house/s/b9"
start_urls = [url + str(offset)+'/']
def parse(self, response):
clears = response.xpath("//div[@class='nlc_details']")
for each in clears:
item = HouseItem.HouseItem()
house_address = each.xpath(".//div[@class='address']")
item['HouseDetailAddress'] = house_address.xpath('.//a/@title').extract()
item['HouseAddress'] = house_address.xpath('.//a/span/text()').extract()
housetypelist = each.xpath(".//div[@class='house_type clearfix']")
item['House_type'] = housetypelist.xpath('string(.)').extract()
house_price = each.xpath(".//div[@class='nhouse_price']")
item['HousePrice'] = house_price.xpath('.//span/text()').extract()
houseeach = each.xpath(".//div[@class='nlcd_name']")
item['HouseName'] = houseeach.xpath('.//a/text()').extract()
item['HouseComment'] = each.xpath(".//span[@class='value_num']/text()").extract()
yield item
if self.offset < 31:
self.offset += 1
yield scrapy.Request(self.url + str(self.offset)+'/', callback = self.parse)
4.数据处理
编写ITEM_PIPELINES处理数据,Scrapy允许数据以JSON、JSON lines、CSV、XML四种格式保存,由于需要进行后续数据统计工作所以保存为CSV格式。在pipeline.py中写入代码:import json
import csv
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class ShuofangwangPipeline(object):
def __init__(self):
self.filename = open('items.csv', 'wb')
self.csvwriter = csv.writer(self.filename, delimiter=',')
self.csvwriter.writerow(['楼盘', '价格', '地址'])
def process_item(self, item, spider):
rows = zip(item['HouseName'], item['HousePrice'], item['HouseAddress'])
for row in rows:
self.csvwriter.writerow(row)
return item
def __init__(self):
self.filename = open('houseData.json', 'w')
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii=False)+",\n"
self.filename.write(text.encode("utf-8").replace("\\t", "").replace("\\n",""))
print text
def close_spider(self,spider):
self.filename.close()
class Pipeline_ToCSV(object):
def __init__(self):
store_file = 'house.csv'
self.file = open(store_file, 'wb')
self.writer = csv.writer(self.file)
self.writer.writerow(("楼盘", "区域","价格","户型","评论" , "地址"))
def process_item(self, item, spider):
housename = str(item['HouseName']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
houseprice = str(item['HousePrice']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
houseaddress = str(item['HouseAddress']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
housedetailaddress = str(item['HouseDetailAddress']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
housetype = str(item['House_type']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
housecomment = str(item['HouseComment']).replace('u\'', '\'').replace("\\t", "").replace("\\n","").replace("[","").replace("]","")
housename1 = housename.decode("unicode-escape")
houseprice1 = houseprice.decode("unicode-escape")
houseaddress1 = houseaddress.decode("unicode-escape")
housedetailaddress1 = housedetailaddress.decode("unicode-escape")
housetype1 = housetype.decode("unicode-escape")
housecomment1 = housecomment.decode("unicode-escape")
print '1----'+housename1
print '2----'+houseprice1
print '3----'+houseaddress1
print '4----'+housedetailaddress1
print '5----'+housetype1
print '6----'+housecomment1
self.writer.writerow((housename1,houseaddress1, houseprice1, housetype1, housecomment1, housedetailaddress1))
return item
def close_spider(self,spider):
self.file.close()
然后在settings.py中加入如下代码:ITEM_PIPELINES = {
#'shuofangwang.pipelines.ShuofangwangPipeline': 1,
'shuofangwang.pipelines.Pipeline_ToCSV':2,
}
ShuofangwangPipeline和Pipeline_ToCSV对应的是pipelines.py中的两个类,第一个是存储为json格式的用于测试使用所以在工程后期对期进行屏蔽处理,第二个是存储CSV格式的。其名字后面的1和2代表着优先级。
代码中使用三个replace方法是因为取出的数据中含有"tn"等,其并不是我们想要的数据所以删除。
并且要 特别注意 的是extract()取出的数据是unicode编码后的数据,所以后期的处理一定要注意,这里在最后使用.decode("unicode-escape")对数据进行转码。
抓取日志信息和处理后的数据如下:
四、总结
本文使用的知识点并不多,主要就是对scrapy框架的运行过程流程的了解,对数据处理时编码的处理。对我来说由于第一次使用python编码爬虫应用,最大的难点就是XPATH对数据的选取和数据存储时编码的处理。听说python3可以忽略编码的问题,后续可以进行尝试。