@概述
@爬取标的
@工程结构简介
@在items.py中创建数据模型
# 个股数据模型
class StockItem(scrapy.Item):
# 股票名称
name = scrapy.Field()
# 股票详细信息
data = scrapy.Field()
@在spiders/目录下创建爬虫源代码my_stock_spider.py
# 定义爬虫类
class MyStockSpider(scrapy.Spider):
# 定义爬虫名称(命令行启动爬虫要用)
name = 'mystockspider'
# 定义起始 url
start_urls = ['http://stock.10jqka.com.cn/']
@定义起始页响应的处理函数parse
# 响应处理函数
# response为start_url所返回的响应对象
def parse(self, response):
@首页响应函数的具体实现
# 响应处理函数
# response为start_url所返回的响应对象
def parse(self, response):
# 提取页面个股超链接
a_list = response.xpath("//div[@id='rzrq']/table[@class='m-table']/tbody/tr/td[2]/a")
# 遍历所有超链接
for a in a_list :
# 提取股票名称、下载数据的url
gp_name = a.xpath("./text()").extract()[0]
link = a.xpath("./@href").extract()[0]
gp_id = link.split('/')[-2]
print("gp_id : ", gp_id)
# 以个股名称作为文件名称,建立或清空一下文件
file_name = "./files/" + gp_name + ".csv"
with open(file_name,"w"):
pass
# 针对每只个股发起爬取子链接的请求
# 对子链接的处理交由download_data函数进行处理
# meta = 转交子链接处理函数所处理的数据
yield scrapy.Request(
url=link,
callback=self.handle_detail,
meta={'page': 1, 'url_base': link, 'name': gp_name,'id':gp_id}
)
@实现详情页的处理函数handle_detail
# 处理个股子链接返回的响应
def handle_detail(self, response):
# 构造数据模型
item = StockItem()
item['name'] = response.meta['name']
item['data'] = ""
# 提取出所有行,然后逐行提取所有单元格中的数据
# 将数据保存到数据模型
tr_list = response.xpath("//table[@class='m-table']/tbody/tr")
for tr in tr_list:
# 提取所有单元格中的数据,以英文逗号连接
text_list = tr.xpath("./td/text()").extract()
onerow = ','.join( [text.strip() for text in text_list] )
# 存储数据到item
item['data'] += onerow+"\n"
# 提交数据模型给pipeline处理
yield item
# 爬取个股分页数据,最多爬取3页
response.meta['page'] += 1
if response.meta['page'] > 3 :
# 不再提交新的请求,爬虫结束
return
# 组装个股分页数据url
url_str = 'http://data.10jqka.com.cn/market/rzrqgg/code/'+response.meta['id']+'/order/desc/page/' + str(response.meta['page']) + '/ajax/1/'
print("url_str = ", url_str)
# 稍事休息后,爬取下一页数据,仍交由当前函数处理
time.sleep(1)
yield scrapy.Request(
url=url_str,
callback=self.handle_detail,
meta={'page': response.meta['page'], 'url_base': url_str, 'name': response.meta['name'],'id':response.meta['id']}
)
@在pipelines.py中定义数据模型处理类
# 处理spider返回的item对象
class StockSavingPipeline(object):
# 初始化方法
def __init__(self):
print("\n"*5,"StockSavingPipeline __init__")
# 处理spider返回的item对象
# item = 爬虫提交过来的数据模型
# spider = 提交item的爬虫实例
def process_item(self, item, spider):
print("\n" * 5, "StockSavingPipeline process_item")
# 提取数据
data = item['data']
file_name = "./files/"+item['name']+".csv"
# 向文件中写入数据
with open(file_name,"a") as file:
file.write(data)
# 如果有多个pipeline,继续向下一个pipeline传递
# 不返回则传递终止
# 这里主要体现一个分工、分批处理的思想
return item
# 对象被销毁时调用
def __del__(self):
print("\n" * 5, "StockSavingPipeline __del__")
@告诉框架爬虫提交的数据对象由谁处理,这里有两种设置方式
ITEM_PIPELINES = {
'myspider.pipelines.WbtcPipeline': 200,
'myspider.pipelines.WbtcPipeline_2': 100,
'myspider.pipelines.StockSavingPipeline': 100,
}
# 声明使用哪些pipelines和下载中间件
# 这里设置的优先级要高于settings.py文件
custom_settings = {
'ITEM_PIPELINES':{'myspider.pipelines.StockSavingPipeline':100},
}
@配置下载中间件
其配置同样有两种方式:配置在settings.py中或配置在爬虫类中,后者的优先级要高于前者
settings.py中的配置如下:
# 配置下载中间件
DOWNLOADER_MIDDLEWARES = {
# 'myspider.middlewares.MyCustomDownloaderMiddleware': 543,
'myspider.middlewares.ProxyMiddleware': 543,
}
# 声明使用哪些pipelines和下载中间件
# 这里设置的优先级要高于settings.py文件
custom_settings = {
'ITEM_PIPELINES':{'myspider.pipelines.StockSavingPipeline':100},
'DOWNLOADER_MIDDLEWARES':{'myspider.middlewares.ProxyMiddleware': 543},
}
@实现下载中间件
class ProxyMiddleware(object):
# 对请求进行预处理
def process_request(self, request, spider):
print("\n" * 5, "ProxyMiddleware process_request")
# 随机选择USER_AGENTS
# 设置 request 对象的头部信息
user_agent = random.choice(USER_AGENTS)
# request.headers.setdefault("User-Agent", user_agent)
request.headers["User-Agent"] = user_agent
# 随机选择 代理ip
# 设置 request 代理 ip
ip = 'http://' + random.choice(PROXY_IP)
# print('user_agent ========== ' + user_agent)
print('Proxy ip ===== ' + ip)
request.meta['proxy'] = ip
# 这里如果return这个request会陷入死循环
# return request
# 对响应进行预处理
def process_response(self, request, response, spider):
print("\n" * 5, "ProxyMiddleware process_response")
print(request.headers)
print(request.meta)
# print(request.url)
# print(response.status)
# print(response.text)
return response
@命令行中跑起来,爬虫就会源源不断地开始爬了
scrapy crawl mystockspider