python爬虫 之 scrapy框架采集2000期彩票数据
最近学习一下数据分析,需要大量的数据,不知道搞啥好就用scrapy框架爬2000期的彩票双色球,看看哪个号码出现的机率大一些。
第一步:
-
在终端切换到想要新建爬虫文件的目录下利用 cd XXXX 进行切换
-
输入scrapy startproject 文件名 ,并利用cd 文件名 切换到新建目录!
我这里新建了一个项目叫gansha 这里成功了就可以看到提示输入cd gansha 进入到项目中 -
输入scrapy genspider 爬虫名 www.XXXXX.com 创建一个爬虫文件,后面的网址可以随便写到时候进入爬虫文件里面可以改。 我这里创建了一个叫ganshane的爬虫文件。
看到这个就说明已经创建好了。我们可以在目录里面看到
这里 gansha 是项目名 里面包含- spiders (里面包含用户自己写的爬虫代码,用的最多),
- int.py (基本上用不着 不管),
- items.py (items代码模块,持久化储存用的),
- middlewares.py (中间件,作用很多UA伪装,代理设置,scrapy结合selenium需要在这里拦截请求然后让 selenium请求url并返回数据。。。等等),
- pipelines.py(管道 pipelines代码模块),
- setings.py(配置文件)
这个是演示流程随便建的一个,我实际创建的是这个
第二步:点击capa.py 打开文件,写爬虫代码
- 进入页面
发现数据都在 tebody 下的 tr 标签里面但是第一个 tr 和第二个 tr 标签是表头的一些信息是我不要的,最后一个tr标签里面是页面信息也不是我要的所以要剔除
所以用xpath解析到
#拿到有效数据的tr标签列表
#xpath解析式不能有‘tebody’
#[2:-1]剔除掉不要的tr标签
tr_list = response.xpath('/html/body/table//tr')[2:-1]
# 遍历列表拿到数据
for tr in tr_list:
day = tr.xpath('./td[1]/text()')[0].extract() #在scrapy里面xpath解析要拿到数据后面都要加上.extract()
center = tr.xpath('./td[2]/text()')[0].extract()#也可以写成extract_first()
red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()
# 这里就拿到了一页的全部期号和双色球的号码
- 首页 url = ‘http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1’
第二页url = ‘http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=2’ 很容易分析出规律
所以
url = 'http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum={}'
n = 1
while n <= 132:
new_url = url.format(n)
n += 1
#绑定回调到解析的函数就可以拿到所有的数据
spider代码:
import scrapy
from caipiaopa.items import CaipiaopaItem #
class CapaSpider(scrapy.Spider):
name = 'capa'
# allowed_domains = ['www.cc.com']
start_urls = ['http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1'] #起始页url
url = 'http://kaijiang.zhcw.com/zhcw/inc/ssq/ssq_wqhg.jsp?pageNum=1{}'
page = 2
def parse(self, response):
tr_list = response.xpath('/html/body/table//tr')[2:-1]
for tr in tr_list:
day = tr.xpath('./td[1]/text()')[0].extract()
center = tr.xpath('./td[2]/text()')[0].extract()
red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()
while self.page <= 132:
new_url = self.url.format(self.page)
self.page += 1
yield scrapy.Request(new_url, callback=self.parse) #绑定回调(自己)
这里只是解析出了数据,还没有持久化存储
第三步:将解析到的数据封装储存在item类型对象中。
- 点开 items.py 。
- 在class CaipiaopaItem(scrapy.Item): 里定义我们解析出来的数据字段,将其定义为item对象的属性
class CaipiaopaItem(scrapy.Item):
day = scrapy.Field()
center = scrapy.Field()
red1 = scrapy.Field()
red2 = scrapy.Field()
red3 = scrapy.Field()
red4 = scrapy.Field()
red5 = scrapy.Field()
red6 = scrapy.Field()
blue = scrapy.Field()
- 再打开爬虫文件 把item类导入 ,并实例化item类型对象,将数据提交。
spider 完整代码:
import scrapy
from caipiaopa.items import CaipiaopaItem
class CapaSpider(scrapy.Spider):
name = 'capa'
# allowed_domains = ['www.cc.com']
start_urls = ['http://kaijiang.zhcw.com/zhcw/html/ssq/list_1.html']
url = 'http://kaijiang.zhcw.com/zhcw/html/ssq/list_{}.html'
page = 2
def parse(self, response):
item = CaipiaopaItem() #实例化item类型对象
tr_list = response.xpath('/html/body/table//tr')[2:-1]
for tr in tr_list:
day = tr.xpath('./td[1]/text()')[0].extract()
center = tr.xpath('./td[2]/text()')[0].extract()
red1 = tr.xpath('./td[3]/em[1]/text()')[0].extract()
red2 = tr.xpath('./td[3]/em[2]/text()')[0].extract()
red3 = tr.xpath('./td[3]/em[3]/text()')[0].extract()
red4 = tr.xpath('./td[3]/em[4]/text()')[0].extract()
red5 = tr.xpath('./td[3]/em[5]/text()')[0].extract()
red6 = tr.xpath('./td[3]/em[6]/text()')[0].extract()
blue = tr.xpath('./td[3]/em[7]/text()')[0].extract()
item['day'] = day #数据封装储存在item类型对象中
item['center'] = center
item['red1'] = red1
item['red2'] = red2
item['red3'] = red3
item['red4'] = red4
item['red5'] = red5
item['red6'] = red6
item['blue'] = blue
yield item #将数据提交给管道
while self.page <= 132:
new_url = self.url.format(self.page)
self.page += 1
yield scrapy.Request(new_url, callback=self.parse)
第四步:在管道里接收item封装的数据,并持久化存储。
- 点开 pipelines.py 写入持久化存储的方法
- 这里我定义了两个类把数据一份存储在本地csv文件,一份存入MYSQL数据库中
from itemadapter import ItemAdapter
import pymysql #导包
class CaipiaopaPipeline: #存储到本地csv文件
fp = None
def open_spider(self,spider): #避免打开文件多次
self.fp = open('./2000期彩票.csv', 'w', encoding='utf-8')
def process_item(self, item, spider):
day = item['day']
center = item['center']
red1 = item['red1']
red2 = item['red2']
red3 = item['red3']
red4 = item['red4']
red5 = item['red5']
red6 = item['red6']
blue = item['blue']
self.fp.write(day+','+center+','+red1+','+red2+','+red3+','+red4+','+red5+','+red6+','+blue+'\n')
return item #传个下一个管道类接受
def close_spider(self,spider):#关闭文件
self.fp.close()
class MysqlPipeline: #写入MYSQL数据库
conn = None
cou = None
def open_spider(self,spider):
self.conn = pymysql.Connect(host='127.0.0.1', port=3306, user='xxx', password='xxx', db='spider', charset='utf8') #定义连接对象
print(self.conn)
def process_item(self, item, spider):
day = item['day']
center = item['center']
red1 = item['red1']
red2 = item['red2']
red3 = item['red3']
red4 = item['red4']
red5 = item['red5']
red6 = item['red6']
blue = item['blue']
#执行的mysql语句 向数据表里面插入数据
sql = 'insert into 彩票 values("%s","%s","%s","%s","%s","%s","%s","%s","%s")'%(day, center, red1, red2, red3, red4, red5, red6, blue)
self.cou = self.conn.cursor() #定义游标对象
try: #事故处理 没有错误就直接提交,插入不成功就回滚到开始的位置
self.cou.execute(sql)
self.conn.commit()
except Exception as e:
print(e)
self.conn.rollback()
return item #传个下一个管道类接受
def close_spider(self,spider): #关闭连接和游标
self.cou.close()
self.conn.close()
第五步:在设置文件中关闭robots协议,定义日志,开启管道类,简单的UA伪装
点开 setings.py
- 简单的ua伪装
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
- 关闭rebots协议,定义日志类型
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR' #只输出错误的日志
- 开启管道
ITEM_PIPELINES = {
'caipiaopa.pipelines.CaipiaopaPipeline': 300, #300,301数字代表优先级,越小优先集越高
'caipiaopa.pipelines.MysqlPipeline': 301,
}
第六步:再次打开终端,进入到项目目录中输入 > scrapy crawl spider capa 回车就ok了
这里数据就采集完了。
本地数据部分截图
这是数据库里部分截图
因为scrapy是基于异步爬取的所以日期都是乱的 MySQL可以按照期号顺序查询
select * from 彩票 order by 期号 ;
这样数据就是按照顺序排好的。
当然本地文件也可以导入到pandas进行排序。。
最后简单的分析下数据
import pandas as pd #数据处理和分析,清洗
#引入数据 处理表头 处理行索引
df = pd.read_csv('2000期彩票.csv', header=None, index_col=0)
# 把红球号码拿出来 行:所有行都要 列:从1到6
red_boll = df.loc[:, 2:7]#用逗号分隔 先拿行再拿列
#把蓝球号码拿出来
blue_boll = df.loc[:, 8]
# #统计每个号码出现的频率 扁平化处理
red_boll_count = pd.value_counts(red_boll.values.flatten())
blue_boll_count = pd.value_counts(blue_boll)
print(red_boll_count, blue_boll_count)
红球数字出现频率
蓝球数字出现频率
感觉都差不多,所以买彩票还是靠运气!!