10行代码爬取全国所有A股/港股/新三板上市公司信息

欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tsaiedu,并注明消息来源,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。

作者:高级农民工
公众号:第2大脑
个人博客:https://www.makcyun.top/

摘要:我们平常在浏览网页中会遇到一些表格型的数据信息,除了表格本身体现的内容以外,可能还想透过表格背后再挖掘些有意思或者有价值的信息。这时,可用python爬虫来实现。本文采用pandas库中的read_html方法来快速准确地抓取网页中的表格数据。

由于本文中含有一些超链接,微信中无法直接打开,所以建议点击最左下角阅读原文阅读,体验更好,也可以复制链接到浏览器打开:

https://www.makcyun.top/web_scraping_withpython2.html

本文知识点:

  • Table型表格抓取

  • DataFrame.read_html函数使用

  • MySQL数据库存储

  • Navicat数据库的使用

1. table型表格

我们在网页上会经常看到这样一些表格,比如:
QS2018世界大学排名:

3901436-2e3adcac8d272bdb
image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

财富世界500强企业排名:

3901436-2c3337d829c7c288.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

IMDB世界电影票房排行榜:

3901436-f6857bb0a8308a5d.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

中国A股上市公司信息:

3901436-50c18e36c7fda20e.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

它们除了都是表格以外,还一个共同点就是当点击右键-定位时,可以看到它们都是table类型的表格。

3901436-0bfd632747ce1520.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

3901436-d2a260d4ff5344bf.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

3901436-47331c0b0fa19212.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

3901436-42ff12e593f68443.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

从中可以看到table类型的表格网页结构大致如下:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1<table class="..." id="...">
2 <thead>
3 <tr>
4 <th>...</th>
5 </tr>
6 </thead>
7 <tbody>
8 <tr>
9 <td>...</td>
10 </tr>
11 <tr>...</tr>
12 <tr>...</tr>
13 <tr>...</tr>
14 <tr>...</tr>
15 ...
16 <tr>...</tr>
17 <tr>...</tr>
18 <tr>...</tr>
19 <tr>...</tr>
20 </tbody>
21</table>

</pre>

先来简单解释一下上文出现的几种标签含义:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1<table> : 定义表格
2<thead> : 定义表格的页眉
3<tbody> : 定义表格的主体
4<tr> : 定义表格的行
5<th> : 定义表格的表头
6<td> : 定义表格单元

</pre>

这样的表格数据,就可以利用pandas模块里的read_html函数方便快捷地抓取下来。下面我们就来操作一下。

2. 快速抓取

下面以中国上市公司信息这个网页中的表格为例,感受一下read_html函数的强大之处。

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1import pandas as pd
2import csv
3
4for i in range(1,178): # 爬取全部177页数据
5 url = 'http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i))
6 tb = pd.read_html(url)[3] #经观察发现所需表格是网页中第4个表格,故为[3]
7 tb.to_csv(r'1.csv', mode='a', encoding='utf_8_sig', header=1, index=0)
8 print('第'+str(i)+'页抓取完成')

</pre>

3901436-de8afe3ae1e93a77
image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

只需不到十行代码,1分钟左右就可以将全部178页共3535家A股上市公司的信息干净整齐地抓取下来。比采用正则表达式、xpath这类常规方法要省心省力地多。如果采取人工一页页地复制粘贴到excel中,就得操作到猴年马月去了。
上述代码除了能爬上市公司表格以外,其他几个网页的表格都可以爬,只需做简单的修改即可。因此,可作为一个简单通用的代码模板。但是,为了让代码更健壮更通用一些,接下来,以爬取177页的A股上市公司信息为目标,讲解一下详细的代码实现步骤。

3. 详细代码实现

3.1. read_html函数

先来了解一下read_html函数的api:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1pandas.read_html(io, match='.+', flavor=None, header=None, index_col=None, skiprows=None, attrs=None, parse_dates=False, tupleize_cols=None, thousands=', ', encoding=None, decimal='.', converters=None, na_values=None, keep_default_na=True, displayed_only=True)
2
3常用的参数:
4io:可以是url、html文本、本地文件等;
5flavor:解析器;
6header:标题行;
7skiprows:跳过的行;
8attrs:属性,比如 attrs = {'id': 'table'};
9parse_dates:解析日期
10
11注意:返回的结果是DataFrame组成的list

</pre>

参考:

1 http://pandas.pydata.org/pandas-docs/stable/io.html#io-read-html
2 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_html.html

3.2. 分析网页url

首先,观察一下中商情报网第1页和第2页的网址:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=1#QueryCondition
2http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=2#QueryCondition

</pre>

可以发现,只有pageNum的值随着翻页而变化,所以基本可以断定pageNum=1代表第1页,pageNum=10代表第10页,以此类推。这样比较容易用for循环构造爬取的网址。
试着把#QueryCondition删除,看网页是否同样能够打开,经尝试发现网页依然能正常打开,因此在构造url时,可以使用这样的格式:
http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=i
再注意一下其他参数:
a:表示A股,把a替换为h,表示港股;把a替换为xsb,则表示新三板。那么,在网址分页for循环外部再加一个for循环,就可以爬取这三个股市的股票了。

3.3. 定义函数

将整个爬取分为网页提取、内容解析、数据存储等步骤,依次建立相应的函数。

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1# 网页提取函数
2def get_one_page(i):
3 try:
4 headers = {
5 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
6 }
7 paras = {
8 'reportTime': '2017-12-31',
9 #可以改报告日期,比如2018-6-30获得的就是该季度的信息
10 'pageNum': i #页码
11 }
12 url = 'http://s.askci.com/stock/a/?' + urlencode(paras)
13 response = requests.get(url,headers = headers)
14 if response.status_code == 200:
15 return response.text
16 return None
17 except RequestException:
18 print('爬取失败')
19
20# beatutiful soup解析然后提取表格
21def parse_one_page(html):
22 soup = BeautifulSoup(html,'lxml')
23 content = soup.select('#myTable04')[0] #[0]将返回的list改为bs4类型
24 tbl = pd.read_html(content.prettify(),header = 0)[0]
25 # prettify()优化代码,[0]从pd.read_html返回的list中提取出DataFrame
26
27 tbl.rename(columns = {'序号':'serial_number', '股票代码':'stock_code', '股票简称':'stock_abbre', '公司名称':'company_name', '省份':'province', '城市':'city', '主营业务收入(201712)':'main_bussiness_income', '净利润(201712)':'net_profit', '员工人数':'employees', '上市日期':'listing_date', '招股书':'zhaogushu', '公司财报':'financial_report', '行业分类':'industry_classification', '产品类型':'industry_type', '主营业务':'main_business'},inplace = True)
28
29 print(tbl)
30 # return tbl
31 # rename将表格15列的中文名改为英文名,便于存储到mysql及后期进行数据分析
32 # tbl = pd.DataFrame(tbl,dtype = 'object') #dtype可统一修改列格式为文本
33
34# 主函数
35def main(page):
36 for i in range(1,page): # page表示提取页数
37 html = get_one_page(i)
38 parse_one_page(html)
39
40# 单进程
41if name == 'main':
42 main(178) #共提取n页

</pre>

上面两个函数相比于快速抓取的方法代码要多一些,如果需要抓的表格很少或只需要抓一次,那么推荐快速抓取法。如果页数比较多,这种方法就更保险一些。解析函数用了BeautifulSoup和css选择器,这种方法定位提取表格所在的id为#myTable04的table代码段,更为准确。

3.4. 存储到MySQL

接下来,我们可以将结果保存到本地csv文件,也可以保存到MySQL数据库中。这里为了练习一下MySQL,因此选择保存到MySQL中。

首先,需要先在数据库建立存放数据的表格,这里命名为listed_company。代码如下:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1import pymysql
2
3def generate_mysql():
4 conn = pymysql.connect(
5 host='localhost', # 本地服务器
6 user='root',
7 password='******', # 你的数据库密码
8 port=3306, # 默认端口
9 charset = 'utf8',
10 db = 'wade')
11 cursor = conn.cursor()
12
13 sql = 'CREATE TABLE IF NOT EXISTS listed_company2 (serial_number INT(30) NOT NULL,stock_code INT(30) ,stock_abbre VARCHAR(30) ,company_name VARCHAR(30) ,province VARCHAR(30) ,city VARCHAR(30) ,main_bussiness_income VARCHAR(30) ,net_profit VARCHAR(30) ,employees INT(30) ,listing_date DATETIME(0) ,zhaogushu VARCHAR(30) ,financial_report VARCHAR(30) , industry_classification VARCHAR(255) ,industry_type VARCHAR(255) ,main_business VARCHAR(255) ,PRIMARY KEY (serial_number))'
14 # listed_company是要在wade数据库中建立的表,用于存放数据
15
16 cursor.execute(sql)
17 conn.close()
18
19generate_mysql()

</pre>

上述代码定义了generate_mysql()函数,用于在MySQL中wade数据库下生成一个listed_company的表。表格包含15个列字段。根据每列字段的属性,分别设置为INT整形(长度为30)、VARCHAR字符型(长度为30) 、DATETIME(0) 日期型等。
在Navicat中查看建立好之后的表格:

3901436-19befd74bfe66715.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

3901436-04564e3dfe01696c
image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

接下来就可以往这个表中写入数据,代码如下:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1import pymysql
2from sqlalchemy import create_engine
3
4def write_to_sql(tbl, db = 'wade'):
5 engine = create_engine('mysql+pymysql://root:******@localhost:3306/{0}?charset=utf8'.format(db))
6 # db = 'wade'表示存储到wade这个数据库中,root后面的*是密码
7 try:
8 tbl.to_sql('listed_company',con = engine,if_exists='append',index=False)
9 # 因为要循环网页不断数据库写入内容,所以if_exists选择append,同时该表要有表头,parse_one_page()方法中df.rename已设置
10 except Exception as e:
11 print(e)

</pre>

以上就完成了单个页面的表格爬取和存储工作,接下来只要在main()函数进行for循环,就可以完成所有总共178页表格的爬取和存储,完整代码如下:

<pre style="margin: auto 5px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-align: justify; text-indent: 0px; text-transform: none; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; color: rgb(87, 87, 87); font-family: Roboto, 'Courier New', Consolas, Inconsolata, Courier, monospace; font-size: 12px; line-height: 1.4em; background-color: rgb(255, 255, 255);">

1import requests
2import pandas as pd
3from bs4 import BeautifulSoup
4from lxml import etree
5import time
6import pymysql
7from sqlalchemy import create_engine
8from urllib.parse import urlencode # 编码 URL 字符串
9
10start_time = time.time() #计算程序运行时间
11
12def get_one_page(i):
13 try:
14 headers = {
15 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
16 }
17 paras = {
18 'reportTime': '2017-12-31',
19 #可以改报告日期,比如2018-6-30获得的就是该季度的信息
20 'pageNum': i #页码
21 }
22 url = 'http://s.askci.com/stock/a/?' + urlencode(paras)
23 response = requests.get(url,headers = headers)
24 if response.status_code == 200:
25 return response.text
26 return None
27 except RequestException:
28 print('爬取失败')
29
30
31def parse_one_page(html):
32 soup = BeautifulSoup(html,'lxml')
33 content = soup.select('#myTable04')[0] #[0]将返回的list改为bs4类型
34 tbl = pd.read_html(content.prettify(),header = 0)[0]
35 # prettify()优化代码,[0]从pd.read_html返回的list中提取出DataFrame
36 tbl.rename(columns = {'序号':'serial_number', '股票代码':'stock_code', '股票简称':'stock_abbre', '公司名称':'company_name', '省份':'province', '城市':'city', '主营业务收入(201712)':'main_bussiness_income', '净利润(201712)':'net_profit', '员工人数':'employees', '上市日期':'listing_date', '招股书':'zhaogushu', '公司财报':'financial_report', '行业分类':'industry_classification', '产品类型':'industry_type', '主营业务':'main_business'},inplace = True)
37
38 # print(tbl)
39 return tbl
40 # rename将中文名改为英文名,便于存储到mysql及后期进行数据分析
41 # tbl = pd.DataFrame(tbl,dtype = 'object') #dtype可统一修改列格式为文本
42
43def generate_mysql():
44 conn = pymysql.connect(
45 host='localhost',
46 user='root',
47 password='******',
48 port=3306,
49 charset = 'utf8',
50 db = 'wade')
51 cursor = conn.cursor()
52
53 sql = 'CREATE TABLE IF NOT EXISTS listed_company (serial_number INT(20) NOT NULL,stock_code INT(20) ,stock_abbre VARCHAR(20) ,company_name VARCHAR(20) ,province VARCHAR(20) ,city VARCHAR(20) ,main_bussiness_income VARCHAR(20) ,net_profit VARCHAR(20) ,employees INT(20) ,listing_date DATETIME(0) ,zhaogushu VARCHAR(20) ,financial_report VARCHAR(20) , industry_classification VARCHAR(20) ,industry_type VARCHAR(100) ,main_business VARCHAR(200) ,PRIMARY KEY (serial_number))'
54 # listed_company是要在wade数据库中建立的表,用于存放数据
55
56 cursor.execute(sql)
57 conn.close()
58
59
60def write_to_sql(tbl, db = 'wade'):
61 engine = create_engine('mysql+pymysql://root:******@localhost:3306/{0}?charset=utf8'.format(db))
62 try:
63 # df = pd.read_csv(df)
64 tbl.to_sql('listed_company2',con = engine,if_exists='append',index=False)
65 # append表示在原有表基础上增加,但该表要有表头
66 except Exception as e:
67 print(e)
68
69
70def main(page):
71 generate_mysql()
72 for i in range(1,page):
73 html = get_one_page(i)
74 tbl = parse_one_page(html)
75 write_to_sql(tbl)
76
77# # 单进程
78if name == 'main':
79 main(178)
80
81 endtime = time.time()-start_time
82 print('程序运行了%.2f秒' %endtime)
83
84
85# 多进程
86# from multiprocessing import Pool
87# if name == 'main':
88# pool = Pool(4)
89# pool.map(main, [i for i in range(1,178)]) #共有178页
90
91# endtime = time.time()-start_time
92# print('程序运行了%.2f秒' %(time.time()-start_time))

</pre>

最终,A股所有3535家企业的信息已经爬取到mysql中,如下图:

3901436-a3d7c44c6d12dbf7.gif
image.gif

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

除了A股,还可以顺便再把港股和新三板所有的上市公司也爬了。后期,将会对爬取的数据做一下简单的数据分析。

最后,需说明不是所有表格都可以用这种方法爬取,比如这个网站中的表格,表面是看起来是表格,但在html中不是前面的table格式,而是list列表格式。这种表格则不适用read_html爬取。得用其他的方法,比如selenium,以后再进行介绍。

3901436-dd9f236d27011c91
image

<figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: 0.544000029563904px; orphans: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em; background-color: rgb(255, 255, 255);"></figcaption>

本文完。

[图片上传失败...(image-a84a78-1539150681665)]

Python爱好者社区历史文章大合集

Python爱好者社区历史文章列表(每周append更新一次)

3901436-219b6b5f8f2763e0
image

福利:文末扫码立刻关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复课程即可获取:

小编的Python入门免费视频课程****!!!

【最新免费微课】小编的Python快速上手matplotlib可视化库!!!

崔老师爬虫实战案例免费学习视频。

陈老师数据分析报告制作免费学习视频。

玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。

3901436-fed4fe4db38bda68
image
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值