摘要
本项目是python课程的课程项目,在简要学习完python和爬虫相关的Scrapy框架后,基于这两者的运用最终完成了对于北京链家网站新房页面的信息进行爬取,并将爬取的数据存放于excel之中,可使用excel或者wps进行查看。
1 引言
在本学期的python课程中,通过网课粗略的掌握了python的基础知识之后,老师提出通过运用python的模块进行附加的学习,于是我选择了Scrapy框架的学习,由此为基础对于链家网站的信息进行了爬取数据的操作,并将爬取的数据保存。
这个项目提高了我的python编程水平,使得我对于爬虫技术的了解更加深入,粗略掌握了如何使用Scrapy框架进行爬虫操作,懂得了python的附加模块的强大之处,也激发了继续学习编程的兴趣。
Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。通常我们可以很简单的通过 Scrapy 框架实现一个爬虫,抓取指定网站的内容或图片。之前在基础学习的时候使用的是Python的request模块也能对网站页面的数据进行爬取,但是request属于页面级爬虫,重点在于页面下载,并发考虑不足,性能较差。
2 系统结构
图1
该项目是基于Scrapy框架来进行的,因此整体的框架如图1所示。由于Scrapy本身封装了大量的内容操作使得代码编写者可以简化自己的代码量。由于大量的封装,在本次项目中只需要修改SPIDERS模块和ITEM PIPELINES模块。
SPIDERS模块是该项目的python模块。在此放入代码。它解析Downloader返回的响应(Response)产生爬取项(scraped item)。产生额外的爬取请求(Request)
ITEM PIPELINES模块,以流水线的方式处理Spider产生的爬取项。由一组操作顺序组成,类似流水线,每个操作都是一个item Pipeline类型。它的操作包括:清理、检验、和查重爬取的HTML数据、将数据存储到数据库或者其他文件中。
Engine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
Scheduler(调度器):它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
简单地理解就是,有要爬去的任务在Scheduler(调度器)排队等待爬取,然后requests请求Internet,spider在Downloader(下载器)里得到响应,最后通过管道保存到相应位置。
3实现代码
scrapy startproject lianjia_bj
建立名为lianjia_bj的工程
scrapy genspider bj lianjia.com
创建一个名为bj的爬虫,搜索的域名范围是lianjia.com
这一部分主要是配置bj.py文件,修改对返回页面的处理,修改对新增URL爬取请求的处理。首先通过对https://bj.lianjia.com/loupan/pg{}网页进行信息提取,获取每个新房的房源信息,再通过yield关键字不断提取标签中的信息。这里信息的提取这里使用的是xpath。
通过浏览器查看网页源代码可以详细去查view-source:https://bj.lianjia.com/loupan/pg1/的代码,然后可以发现li"标签后面紧跟的标签中的属性值就是每个房源的详情信息。使用xpath进行一一提取即可。
代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import scrapy
import time
from lianjia_bj.items import LianjiaBjItem
import random
class BjSpider(scrapy.Spider):
name = 'bj'
# allowed_domains = ['bj.lianjia.com'] # 爬取的域,防止跳转到其他链接
start_urls = ['https://bj.fang.lianjia.com/loupan/pg1'] # 目标URL
def parse(self, response):
divs = response.xpath('/html/body/div[3]/ul[2]/li')
for div in divs:
item = LianjiaBjItem()
item['title'] = div.xpath('./div/div[1]/a/text()')[0].extract()
item['area'] = div.xpath('./div/div[3]/span/text()')[0].extract()
item['house_leixing'] = div.xpath('./div/div[1]/span[1]/text()')[0].extract()
item['house_xiaoshou'] = div.xpath('./div/div[1]/span[2]/text()')[0].extract()
item['house_qu'] = div.xpath('./div/div[2]/span[1]/text()')[0].extract()
item['house_xiangzhen'] = div.xpath('./div/div[2]/span[2]/text()')[0].extract()
item['house_dizhi'] = div.xpath('./div/div[2]/a/text()')[0].extract()
house_huxing1=div.xpath('./div/a/span/text()')
house_maidian1 = div.xpath('./div/div[5]/span/text()')
item['money_danjia'] = div.xpath('./div/div[6]/div[1]/span[1]/text()')[0].extract()
item['money_zongjia'] = div.xpath('./div/div[6]/div[2]/text()')[0].extract()
if len(house_huxing1)==1:
item['house_huxing']=house_huxing1[0].extract()
elif len(house_huxing1)==2:
item['house_huxing'] = house_huxing1[0].extract()+'/'+house_huxing1[1].extract()
elif len(house_huxing1) == 3:
item['house_huxing'] = house_huxing1[0].extract() + '/'+house_huxing1[1].extract()+ '/'+house_huxing1[2].extract()
elif len(house_huxing1) == 4:
item['house_huxing'] = house_huxing1[0].extract() + '/'+house_huxing1[1].extract()+ '/'+house_huxing1[2].extract()+ '/'+house_huxing1[3].extract()
else:
item['house_huxing'] = house_huxing1[0].extract()
if len(house_maidian1)==1:
item['house_maidian']=house_maidian1[0].extract()
elif len(house_maidian1)==2:
item['house_maidian'] = house_maidian1[0].extract()+'/'+house_maidian1[1].extract()
elif len(house_maidian1) == 3:
item['house_maidian'] = house_maidian1[0].extract() + '/'+house_maidian1[1].extract()+ '/'+house_maidian1[2].extract()
elif len(house_maidian1) == 4:
item['house_maidian'] = house_maidian1[0].extract() + '/'+house_maidian1[1].extract()+ '/'+house_maidian1[2].extract()+ '/'+house_maidian1[3].extract()
else:
item['house_maidian'] = house_maidian1[0].extract()
# print(title,area,house_dizhi,house_huxing,house_leixing,house_maidian,house_qu,house_xiangzhen,house_xiaoshou,money_danjia,money_zongjia)
print(house_huxing1)
time.sleep(1)
yield item
next_url = 'https://bj.fang.lianjia.com/loupan/pg{page}'
# time.sleep(random(1,3))
for page in list(range(2, 5)): # 控制页数
yield scrapy.Request(next_url.format(page=page),callback=self.parse) # 回调
这一部分主要是配置pipelines.py文件,主要定义对LianjiaBjPipeline_csv
处理类以及通过setting.py文件配置ITEM_PIPLINES选项。这里主要是将爬取的数据放入excel之中,首先建立表头,最后再将爬取的数据进行插入。
代码如下:
from openpyxl import Workbook
class LianjiaBjPipeline_csv(object): # Excel
def __init__(self):
self.wb = Workbook()
self.ws = self.wb.active
self.ws.append(['title','area','house_dizhi','house_huxing','house_leixing','house_maidian','house_qu','house_xiangzhen','house_xiaoshou','money_danjia','money_zongjia'])
def process_item(self, item, spider):
line = [item['title'],item['area'], item['house_dizhi'], item['house_huxing'],item['house_leixing'],item['house_maidian'], item['house_qu'], item['house_xiangzhen'],item['house_xiaoshou'],item['money_danjia'], item['money_zongjia']]
self.ws.append(line)
self.wb.save('bjxinfang.xlsx')
return item
def close_spider(self, spider):
self.wb.save('bjxinfang.xlsx')
这里是setting.py要修改的部分,让框架能够找到我们在piplines中新建的类
ITEM_PIPELINES = {
'lianjia_bj.pipelines.LianjiaBjPipeline_csv': 100,
}
4 爬虫实现
新建一个scrapy框架的运行程序main.py,这样就可以直接运行,不用在通过cmd命令运行了,方便快捷。代码如下:
from scrapy import cmdline
cmdline.execute ('scrapy crawl bj'.split())
4.1运行爬虫代码
最终结果: