python爬虫成长之路(三):基础爬虫架构及爬取证券之星全站行情数据
爬虫成长之路(一)里我们介绍了如何爬取证券之星网站上所有A股数据,主要涉及网页获取和页面解析的知识。爬虫成长之路(二)里我们介绍了如何获取代理IP并验证,涉及了多线程编程和数据存储的知识。此次我们将在前两节的基础上,对证券之星全站的行情数据进行爬取。第一节的思路爬一个栏目的数据尚可,爬上百个栏目的数据工作量就有点大了。下面我们先介绍下基础的爬虫架构。
本文主要包含爬虫框架六大基础模块,分别为爬虫调度器、URL下载器、URL管理器、HTML下载器、HTML解析器、数据存储器。功能分析如下
爬虫调度器:主要负责统筹其他四个模块的工作。
URL下载器:主要负责下载需要爬取数据的URL链接。
URL管理器:负责管理URL链接,维护已经爬取的URL集合和未爬取的URL集合,提供获取新URL链接的接口。
HTML下载器:用于从URL管理器中获取未爬取的URL链接并下载HRML网页。
HTML解析器:用户从HTML下载器中获取已经下载的HTML网页,解析出有效数据交给数据存储器。
数据存储器:用于将HTML解析器解析出来的数据通过文件或者数据库的形式储存起来。
为了方便理解,以下是基础爬虫框架运行流程示意图
此处介绍文件夹,下面,我们对这6大模块进行详细的介绍。
一、URL下载器
URL下载器包含两步,首先下载网站左侧导航栏的URL,然后通过导航栏的URL获取每个子栏目包含的链接列表。
下面是获取左侧导航栏所有链接并生成导航文件的代码
# -*- coding: utf-8 -*-
import pandas as pd
import urllib.request
from bs4 import BeautifulSoup
import re
import os
class get_catalog(object):
'''生成和操作导航文件'''
def save_catalog(self):
'''获得证券之星左侧自导航的内容和网址并保存'''
#获取网页内容
url = 'http://quote.stockstar.com'
request =urllib.request.Request(url = url)
response = urllib.request.urlopen(request)
content = response.read().decode('gbk')
#截取左侧导航内容
soup = BeautifulSoup(content,"lxml")
soup = BeautifulSoup(str(soup.find_all('div',class_ = "subMenuBox")),"lxml")
#初始化一级子目录和二级子目录的数据框
catalog1 = pd.DataFrame(columns = ["cata1","cata2","url2"])
catalog2 = pd.DataFrame(columns = ["url2","cata3","url3"])
#整理目录内容和其对应的链接
index1 = 0;index2 = 0
for content1 in soup.find_all('div',class_ = re.compile("list submenu?")):
cata1 = re.findall('>(.*?)<',str(content1.h3.a))
for content2 in content1.find_all('dl'):
cata2 = re.findall('>(.*?)<',str(content2.dt.a).replace('\r\n',''))
url2 = url + content2.dt.a['href']
catalog1.loc[index1] = {'cata1':cata1[0],'cata2':cata2[0].split()[0],'url2':url2}
index1 += 1
for content3 in content2.find_all('li'):
cata3 = re.findall('·(.*?)<',str(content3.a))
url3 = url + content3.a['href']
catalog2.loc[index2] = {'url2':url2,'cata3':cata3[0],'url3':url3}
index2 += 1
#对一级子目录表和二级子目录表做表连接并保存
catalog = pd.merge(catalog1,catalog2,on='url2',how='left')
catalog.to_csv('catalog.csv')
def load_catalog(self):
'''判断导航文件是否存在并载入'''
if 'catalog.csv' not in os.listdir():
self.save_catalog()
print('网址导航文件已生成')
else:
print('网址导航文件已存在')
catalog = pd.read_csv('catalog.csv',encoding='gbk',usecols=range(1,6))
print("网址导航文件已载入")
return(catalog)
def index_info(self,catalog,index):
'''创建每行的行名,作为存入数据库的表名,并获取每行终端的网址链接'''
if str(catalog.loc[index]['cata3'])=='nan':
table_name = catalog.loc[index]['cata1'] + '_' + catalog.loc[index]['cata2']
url = catalog.loc[index]['url2']
else:
#+、()等符号不能作为数据库表名,得替换或剔除
if '+' in catalog.loc[index]['cata3']:
cata3 = catalog.loc[index]['cata3'].replace('+','')
table_name = catalog.loc[index]['cata1'] +