思路:
1、麦田网租房信息url=http://bj.maitian.cn/zfall/
2、获取标题描述、房屋面积信息、位置信息,房屋价格及二层url的细节评价
3、设置翻页循环
4、使用xpath解析数据
5、首页和细节页数据存入同一张表里
遇到的问题:
二层页面右键无法点击(简单的反爬)
一、准备工作
- 创建一个scrapy project:
scrapy startproject MTZF
- 创建spider file
scrapy genspider maitian maitian.com
二、构建框架
(1)items.py / 定义item
import scrapy
class ItemItem(scrapy.Item):
#声明所有需要的item,与spider里获取的一一对应
title = scrapy.Field()
info = scrapy.Field()
location= scrapy.Field()
price = scrapy.Field()
detail = scrapy.Field()
(2) spider.py
import scrapy
from ITEM.items import ItemItem
class MaitianSpider(scrapy.Spider):
name = 'maitian'
allowed_domains = ['maitian.cn']
url = 'http://bj.maitian.cn/zfall/PG{}'
#从第1页开始爬取
page = 1
start_urls = [url.format(page)]
def parse(self, response):
room_list = response.xpath('//div[@class="list_wrap"]/ul/li[@class="clearfix"]')
#获取所有的房屋信息列表,得到的是一个可遍历对象
#设置一个if判断语句,当没有获取到数据时打破翻页循环
if not roomlist:
return None
#遍历roomlist,取出需要的标签文本数据
for i in roomlist:
item = ItemItem()
#引入item
#标题
item['title'] = i.xpath('./div[@class="list_title"]/h1/a/text()').extract_first().strip()
#scrapy框架中xpath语句得到的对象需要使用extract提取器提取出
#因为得到的是一个列表,取出仅有的第一个元素,去除多余的空格
#概况
item['info'] = ','.join(i.xpath('./div[@class="list_title"]/p/span/text()').extract()[:-2]).replace(' ','')
#观察有几个同级别的span标签,前面几个是想要的概况,最后两个是位置信息,这里我想把他们分开存储,使用了列表的切片
#取出的text是由空格间隔的词组组成的,使用逗号替代空格
#位置
item['location'] = ','.join(i.xpath('./div[@class="list_title"]/p/span/text()').extract()[-2:]).strip()
#同级span标签的后两个是我定义的location数据
#价格
price = i.xpath('./div[@class="list_title"]/div[@class="the_price"]//span/text()').extract_first()
unit = i.xpath('./div[@class="list_title"]/div[@class="the_price"]//strong/text()').extract_first()
item['price'] = price + unit
#为了格式好看,把价格单位也拼接上
#获取二层url,爬取评价
detail_url = 'http://bj.maitian.cn' + i.xpath('./a/@href').extract_first().strip()
#直接获取的二层url:1、设置了大量空格,需要去除;2、不完整,需要拼接。
yield scrapy.Request(detail_url,meta={'detail':item},callback=self.parse_info)
#准备把二层获取的评价与上面获取的信息放入同一个item里,这里item先不返回,通过request传给下一个函数
#request通过meta以字典形式传递对象,自定义key-value,在下一步使用key值将value取出
def parse_info(self,response):
#解析二层代码时遇到的问题:二层网页无法右键点击,一个反爬点
#解决:访问detail_url,保存html,从本地查看,然后解析
# with open('bj.html','wb')as f:
# f.write(response.body)
#这一步做一次就可以了,隐藏掉
#承接上一步传来的item
item = response.meta['detail']
#获取详情页评价
item['detail']=response.xpath('.//div[@class="hc_left clearfix"]//label[@class="all_font"]/text()').extract_first()
#获取完整想要的数据后,设置自动翻页,拼接第一层url的下一页的地址,继续发送请求、解析数据
self.page += 1
url = self.url.format(self.page)
yield item
yield scrapy.Request(url,callback=self.parse)
(3) middlewares.py
import random
#操控request参数的中间件
#因为下载中间件在后面,所以添加User-Agent使用DownloaderMiddleware
class ItemDownloaderMiddleware(object):
def __init__(self):
#复制了一个ug列表
self. user_agent_list = ["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"]
#改写重要的一步process_request,传入请求头参数
def process_request(self, request, spider):
ug = random.choice(self.user_agent_list)
#从ug池里随机选出一个user-agent
#可以自行添加设置if语言防止重复
request.headers['User-Agent'] = ug
#将选出的ug传给request
return None
def process_response(self, request, response, spider):
#这一步可以不改写,这里写来验证user-agent是否添加成功
print('使用了User-Agent:',request.headers['User-Agent'])
return response
(4)pipelines.py
#数据持久化的管道,将数据保存到非关系型数据库MongoDB中
import pymongo
class ItemPipeline(object):
def __init__(self):
client = pymongo.MongoClient()
#连接数据库,host和port参数使用默认值,这里没有传入
#host地址:127.0.0.1
#port端口号:27017
mydb = client['test']
#选择数据库test
self.collection = mydb['maitian']
#选择表maitian
def process_item(self, item, spider):
data = dict(item)
#将返回的item转为字典格式,MongoDB是以键值对的形式保存数据的
self.collection.insert(data)
#python与MongoDB的交互之 插入数据
return item
(5)一切准备就绪别忘记setting
一般写好一部分代码就开启相应的设置,以防忘记
#设置日志,级别为只看warning
LOG_FILE = 'maitian.log'
LOG_LEVEL = 'WARNING'
#不遵守robot协议
ROBOTSTXT_OBEY = False
#下载延时,太快会被反爬
DOWNLOAD_DELAY = 3
#打开下载中间件,名称要与你设置的一致
DOWNLOADER_MIDDLEWARES = {
'ITEM.middlewares.ItemDownloaderMiddleware': 543,
}
#打开item管道
ITEM_PIPELINES = {
'ITEM.pipelines.ItemPipeline': 300,
}
三、运行spider
(1)打开MongoDB服务器,启动客户端
sudo mongod
mongo
(2)运行spider
scrapy crawl maitian
如果需要数据可视化为csv格式:
mongoexport -d test -c maitian -f title,info,location,price,detail --csv -o ./maitian.csv