• 实战项目 1:5 行代码爬取国内所有上市公司信息


     

     

    实战项目 1:5 行代码爬取国内所有上市公司信息

    Python入门爬虫与数据分析


    在正式开始这门专栏课的学习之前,我们先来看一个简单的爬虫案例。兴趣是最好的老师,当你对爬虫产生兴趣的时候,才会更有动力去学它。

     

    ▌入门爬虫

    首先来看要爬取的目标网站:http://s.askci.com/stock/1/

    网页中有一张表格,内容是全国上市公司相关信息,整个表格有 180 页。我们需要做的工作就是,用几十秒钟把表格所有数据爬取下来,接着保存到本地文件。试想如果不会爬虫,要完成这份工作得费多大力气。

    为什么要以这个网页作为第一个爬虫案例呢?有两点原因:

    • 这类表格型数据在网页中非常常见,学会这个爬虫就能爬取一大类的网页数据,很实用。
    • 这个爬虫很简单,5 行代码就可以实现。

    好,下面我们就正式开始。

     

    ▌简版代码

    我们可以先写一个简版代码,只写最核心的,就是抓数据,其他的诸如:下载速度、存储方式、代码条理性等先不管,这样代码写起来容易上手,能增强信心。

    下面来看看如何用 5 行代码抓取上面表格中的所有数据。

     
    1. 1 import pandas as pd
      2 import csv
      3 for i in range(1,178): # 爬取全部页
      4 tb = pd.read_html('http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i)))[3]
      5 tb.to_csv('company.csv', mode='a', encoding='utf_8_sig', header=1, index=0)

    如果你不太明白上面代码意思,没有关系,后面的课程会介绍。现在只需要动手敲一遍,然后点击运行,几十秒钟之后在本地就可以看到一个名为 company.csv 的文件,打开结果见下表:

    这样我们就爬取完了所有数据。怎么样,是不是觉得爬虫有点意思,没有想象中那么难。写几行代码,剩下的交给电脑就好了。

    上面的爬虫有些单薄,还可以更完善一些,具体考虑这几个方面:

     

    ▌完善代码

    • 增加代码灵活性

    上面代码中的 URL 参数是固定的,比如reportTime=2017-12-31 表示爬取的是这一日期的数据,如果想爬取其他时期,需要在 URL 中去修改,不够灵活方便。怎么改变呢,也很简单,可以将日期赋予一个变量,在 URL 外部单独修改变量来爬取不同日期的数据。

    • 增添存储方式

    上面文件保存方式选择了 csv 文件,更为常见的方式是保存到数据库中,比如 MySQL、MongoDB 等,这里我们可以选择保存到 MySQL 中,当练习数据库的使用。

    • 加快爬取速度

    上面的代码是单进程爬取,爬取 180 页速度相对较慢,要想加快爬取速度可以使用多进程方式。

    • 增加异常处理

    上面代码没有任何异常处理措施,一旦爬取失败,我们找不到原因。最好是增加代码异常捕捉方式,可以使用 try except 、if 等语句,让代码更健壮。

    考虑上述几方面,代码完善如下:

     
    1.  1 import requests
       2 import pandas as pd
       3 from bs4 import BeautifulSoup
       4 from lxml import etree
       5 import time
       6 import pymysql
       7 from sqlalchemy import create_engine
       8 from urllib.parse import urlencode # 编码 URL 字符串
       9 start_time = time.time() #计算程序运行时间
      10 def get_one_page(i,date):
      11 try:
      12 headers = {
      13 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
      14 }
      15 paras = {
      16 'reportTime': date,
      17 #可以改报告日期,比如 2018-6-30 获得的就是该季度的信息
      18 'pageNum': i #页码
      19 }
      20 url = 'http://s.askci.com/stock/a/?' + urlencode(paras)
      21 response = requests.get(url,headers = headers)
      22 if response.status_code == 200:
      23 return response.text
      24 return None
      25 except RequestException:
      26 print('爬取失败')
      27 def parse_one_page(html):
      28 soup = BeautifulSoup(html,'lxml')
      29 content = soup.select('#myTable04')[0] #[0]将返回的 list 改为 bs4 类型
      30 tbl = pd.read_html(content.prettify(),header = 0)[0]
      31 # prettify()优化代码,[0]从 pd.read_html 返回的 list 中提取出 DataFrame
      32 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)
      33 return tbl
      34 def generate_mysql():
      35 conn = pymysql.connect(
      36 host='localhost',
      37 user='root',
      38 password='******', #修改为你的密码
      39 port=3306,
      40 charset = 'utf8',
      41 db = 'wade') #修改为自己的数据库
      42 cursor = conn.cursor()
      43 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))'
      44 cursor.execute(sql)
      45 conn.close()
      46 def write_to_sql(tbl, db = 'wade'):
      47 engine = create_engine('mysql+pymysql://root:******@localhost:3306/{0}?charset=utf8'.format(db))
      48 try:
      49 tbl.to_sql('listed_company2',con = engine,if_exists='append',index=False)
      50 # append 表示在原有表基础上增加,但该表要有表头
      51 except Exception as e:
      52 print(e)
      53 def main(page):
      54 generate_mysql()
      55 date = '2017-12-31'
      56 for i in range(1,page):
      57 html = get_one_page(i,date)
      58 tbl = parse_one_page(html)
      59 write_to_sql(tbl)
      60 # # 单进程
      61 # if __name__ == '__main__':
      62 # main(178)
      63 # endtime = time.time()-start_time
      64 # print('程序运行了%.2f 秒' %endtime)
      65 # # 多进程
      66 from multiprocessing import Pool
      67 if __name__ == '__main__':
      68 pool = Pool(4)
      69 pool.map(main, [i for i in range(1,178)]) #共有 178 页
      70 endtime = time.time()-start_time
      71 print('程序运行了%.2f 秒' %(time.time()-start_time))

    代码从原先的 5 行增加到几十行,针对每个点去完善,代码编写过程也很自然,如果一上来就写出这几十行代码,新手可能很快就会放弃。

    数据爬取下来之后,可以说爬虫工作就完成了,不过,还可以进一步做一些数据分析,比如像下面这样:

    以上,我们从一个简单的爬虫案例入手,初步了解了爬虫是怎么回事,能干什么事。代码具体编写知识,后续课程一一介绍。

    文中完整代码和素材,可以在下方链接中得到:

    https://github.com/makcyun/web_scraping_with_python/tree/master/10%E8%A1%8C%E4%BB%A3%E7%A0%81%E7%88%AC%E5%8F%96%E5%85%A8%E5%9B%BDA%E8%82%A1%E6%B8%AF%E8%82%A1%E6%96%B0%E4%B8%89%E6%9D%BF%E4%B8%8A%E5%B8%82%E5%85%AC%E5%8F%B8%E4%BF%A1%E6%81%AF

    另外,如果想更充分地学习本专栏课程,可以参考《Python3 网络爬虫开发实战》这本书。

    下一节课,我们再用一个实战来学习爬虫基本技法。

    +
     
     
    没有借口
  • 相关阅读:
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    【mongoDB实战】mongo集群---主从复制篇
    【mongoDB实战】聚合管道--$unwind
    【mongoDB实战】聚合管道--$unwind
    【mongoDB实战】mongoDB数据导入和导出
    【mongoDB实战】mongoDB数据导入和导出
    【mongoDB实战】mongoDB数据备份和还原
    【mongoDB实战】mongoDB数据备份和还原
    【Restful】三分钟彻底了解Restful最佳实践
  • 原文地址:https://www.cnblogs.com/wutao1935/p/11230058.html
Copyright © 2020-2023  润新知