爬虫成长之路(一)里我们介绍了如何爬取证券之星网站上所有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'] +