Python 网络爬虫笔记11 – Scrapy 实战
Python 网络爬虫系列笔记是笔者在学习嵩天老师的《Python网络爬虫与信息提取》课程及笔者实践网络爬虫的笔记。
课程链接:Python网络爬虫与信息提取
参考文档:
Requests 官方文档(英文)
Requests 官方文档(中文)
Beautiful Soup 官方文档
re 官方文档
Scrapy 官方文档(英文)
Scrapy 官方文档(中文)
股票数据 Scrapy 爬虫
介绍:
- 爬取中国股市的股票信息, 从东方财富网获取股票列表,根据股票列表逐个到百度股票获取个股信息根据股票列表逐个到百度股票获取个股信息,将结果存储到文件将结果存储到文件
- 东方财富网:http://quote.eastmoney.com/stocklist.html
- 百度股票:https://gupiao.baidu.com/stock/
- 单个股票:https://gupiao.baidu.com/stock/sz002439.html
步骤:
-
建立工程和 Spider 模板
# cmd 依次输入以下命令 scrapy startproject scrapy_stocks cd scrapy_stocks scrapy genspider stocks gupiao.baidu.com
-
编写Spider,处理链接爬取和页面解析
- 配置stocks.py文件
- 修改对返回页面的处理
- 修改对新增URL爬取请求的处理
-
编写ITEM Pipelines,处理信息存储
- 配置pipelines.py文件
- 定义对爬取项(Scraped Item)的处理类
- 配置ITEM_PIPELINES选项
# 在settings.py文件中配置ITEM_PIPELINES选项,改为自己写的类名 ITEM_PIPELINES = {'scrapy_stocks.pipelines.ScrapyStocksPipeline': 300,}
-
运行爬虫
# cmd输入以下命令 scrapy crawl stocks
-
配置优化
修改 settings.py文件的相应项
项 说明 NCURRENT_REQUESTS Downloader最大并发请求下载数量,默认32 NCURRENT_ITEMS Item Pipeline最大并发ITEM处理数量,默认100 NCURRENT_REQUESTS_PER_DOMAIN 每个目标域名最大的并发请求数量,默认8 NCURRENT_REQUESTS_PER_IP 每个目标IP最大的并发请求数量,默认0,非0有效
stocks.py 文件:
# -*- coding: utf-8 -*-
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = "stocks"
start_urls = ['http://quote.eastmoney.com/stocklist.html']
def parse(self, response):
"""
解析 Response 对象,产生额外的爬取请求
"""
for href in response.css('a::attr(href)').extract():
try:
stock = re.findall(r's[hz]\d{6}', href)[0]
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
yield scrapy.Request(url, callback=self.parse_stock)
except:
continue
def parse_stock(self, response):
"""
解析 Response 对象
"""
info_dict = {}
stock_info = response.css('.stock-bets')
name = stock_info.css('.bets-name').extract()[0]
key_list = stock_info.css('dt').extract()
value_list = stock_info.css('dd').extract()
for i in range(len(key_list)):
key = re.findall(r'>.*</dt>', key_list[i])[0][1:-5]
try:
val = re.findall(r'\d+\.?.*</dd>', value_list[i])[0][0:-5]
except:
val = '--'
info_dict[key] = val
info_dict.update({'股票名称': re.findall('\s.*\(', name)[0].split()[0] + re.findall('\>.*\<', name)[0][1:-1]})
yield info_dict
pipelines.py 文件:
class BaiduStocksPipeline(object):
"""
直接返回解析结果
"""
def process_item(self, item, spider):
return item
class BaiduStocksInfoPipeline(object):
"""
保存解析结果到文件
"""
def open_spider(self, spider):
self.f = open('BaiduStockInfo.txt', 'w')
def close_spider(self, spider):
self.f.close()
def process_item(self, item, spider):
try:
line = str(dict(item)) + '\n'
self.f.write(line)
except:
pass
return item
settings.py 文件:
ITEM_PIPELINES = {
'scrapy_stocks.pipelines.BaiduStocksInfoPipeline': 300,
}