欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

利用Python爬取国家水稻数据中心的品种数据

程序员文章站 2022-03-11 16:35:01
...

利用Python爬取国家水稻数据中心的品种数据

  • 一.页面获取
    python可以进行对网页的访问,主要用到requests,beautifulsoup4包。
    首先新建一个page的py文件,用来获取页面的数据。
import requests
import bs4
import re
import math

def get_page(url, coding):  # 创建一个函数,用来获取BS4格式的文档,并返回整个页面。
    # 主要有两个参数,url代表网页地址,coding代表页面编码格式
    from fake_useragent import UserAgent # 调用UserAgent 包,获取用户代理头的值,避免被屏蔽。
    ua = UserAgent()
    headers = {"User-Agent": ua.random}
    r = requests.get(url, headers=headers,timeout=15)
    r.encoding = coding  # 用GB2312解码文档
    rt = r.text
    soup = bs4.BeautifulSoup(rt, 'lxml')  # HTML文档字符串  HTML解析器  HTML文档编码
    return soup

def get_numdata(data):  # 创建一个函数,用来接收BS4格式的文档,并返回具体的页数。
    con = data.find_all(name='caption') # 查询文档中 name='caption' 的标签
    com = con[0].next.next  # 查询历年审定品种的数量
    s = re.findall("\d+", com)[0]  # 正则表达式提取数字
    z = math.floor((int(s) - 1) / 35) + 1  # 计算页数,当数字是35的时候,需要-1除以35再+1得到1页
    # 为什么是35,是因为页面中的数据共35行
    return z

def get_head(data):  # 创建一个函数,用来接收BS4格式的文档,并返回Excel的表头。
    Head = data.find_all(name='tr', align="left")  # 查表头:搜索文档中的tr标签,且符合类 align="left" 的tag
    x = Head[0].contents  # 获取标签 tr 的内容
    y = '网址'
    head_1 = [x[0].next.next, x[1].next.next, y, x[2].next.next, x[3].next.next, x[4].next.next, x[5].next.next]
    head_2 = ['全生育期', '株高', '穗长', '每亩有效穗', '每穗总粒数', '结实率', '千粒重',
              '整精米率', '垩白粒率', '垩白度', '直链淀粉含量', '胶稠度', '长宽比']
    head = head_1 + head_2  # 得到Excel表头的list
    return head

def get_province(data):  # 用来获取省份和网址并建立字典
    url2 = 'http://www.ricedata.cn/variety/' # 获取省份的网址前缀
    con = data.find_all(name='a', target="_blank")  # 查省份:搜索文档中的a标签,且target="_blank"的tag
    province = {} # 建立一个代表省份的空字典
    for i in con[:-1]:
        if type(i) is bs4.element.Tag and i.string is not None:
            # 判断字符串的格式且不为空值
            z = i.string.replace(u'\u3000', '') # 省份名称
            y = url2 + i['href'] # 具体的网址
            province[z] = y # 追加数据 省份:网址 到字典province中
        else:
            continue
    province.pop(' ')  # 删除空值,也就是某些不种水稻的省份,如*,香港等
    return province

def get_detailed_data(data):  # 获取每个品种的详细数据
    receive_data1 = str(data.find_all(name='td', colspan="2")[0].contents)
    receive_data = receive_data1.replace("\\r\\n", "")  # 去除字符串中的换行符
    full_growth_period = re.findall('(?<=全生育期)[\d+\.\d]*', receive_data)
    plant_height = re.findall('(?<=株高)[\d+\.\d]*', receive_data)
    spike_length = re.findall('(?<=穗长)[\d+\.\d]*', receive_data)
    effective_panicles_per_acre = re.findall('(?<=每亩有效穗数)[\d+\.\d]*', receive_data)
    grains_per_panicle = re.findall('(?<=每穗总粒数)[\d+\.\d]*', receive_data)
    seed_setting_rate = re.findall('(?<=结实率)[\d+\.\d]*', receive_data)
    thousand_grain_weight = re.findall('(?<=千粒重)[\d+\.\d]*', receive_data)
    head_rice_rate = re.findall('(?<=整精米率)[\d+\.\d]*', receive_data)
    chalky_rice_rate = re.findall('(?<=垩白粒率)[\d+\.\d]*', receive_data)
    chalkiness_degree = re.findall('(?<=垩白度)[\d+\.\d]*', receive_data)
    amylose_content = re.findall('(?<=直链淀粉含量)[\d+\.\d]*', receive_data)
    gel_consistency = re.findall('(?<=胶稠度)[\d+\.\d]*', receive_data)
    length_width_ratio = re.findall('(?<=长宽比)[\d+\.\d]*', receive_data)
    return [full_growth_period, plant_height, spike_length, effective_panicles_per_acre, grains_per_panicle,
            seed_setting_rate, thousand_grain_weight, head_rice_rate, chalky_rice_rate, chalkiness_degree,
            amylose_content, gel_consistency, length_width_ratio]

def get_dedata(de_data):  # 将品种的详细数据转化成一个list
    dedata = []
    for i in de_data:
        if len(i) > 0:
            x = list(filter(None, i))
            # filter()为已知的序列的每个元素调用给定的布尔函数,调用中,返回值为非零的元素将被添加至一个列表中
            if len(x) > 0:
                dedata.append(x[0])
            else:
                dedata.append(None)
        else:
            dedata.append(None)
    return dedata


  • 二.数据处理
    然后新建一个 rdata 的 py 文件,用来处理数据。
def get_rice(num, data):  # 该函数用来从data中获取35行水稻数据
    url = 'http://www.ricedata.cn/variety'
    data1 = data[num + 0].text  # 序号
    data2 = data[num + 1].text  # 品种
    data3 = url + str(data[num + 1].contents[0]['href'][2:])  # 网址
    data4 = data[num + 2].text  # 亲本来源
    data5 = data[num + 3].text  # 类型
    data6 = data[num + 4].text  # 选育单位
    data7 = data[num + 5].text  # 审定编号
    return data1, data2, data3, data4, data5, data6, data7

def get_ricedata(ricedata): # 该函数用来获取每一行的数据
    x = []
    count = 0
    data_len = len(ricedata)
    while count + 5 < data_len:
        for i in get_rice(num=count, ricedata=data):
            x.append(i)
        count += 6 # count+6表示每一行有6个数据
    return x

def get_data(soup):  # 用来查询品种数据,页面的品种的行和列
    soup_data = soup.find_all('td', style="border-top:dotted silver 1px")
    data = get_ricedata(data=soup_data)
    return data
  • 三.数据保存
    新建一个 rice.py 的文件
    将爬取到的数据保存到Excel中, 具体的路径为rice.py的文件所在的路径。
import datetime
import xlwt
import page
import rdata
import time
import os

print('请求数据')
url = 'http://www.ricedata.cn/variety/index.htm'
pro_data = page.get_page(url=url, coding='utf-8')
pro = page.get_province(data=pro_data)
workbook = xlwt.Workbook(encoding='utf-8')  # 创建一个workbook 设置编码

for key, value in pro.items():
    starttime = datetime.datetime.now()  # 计算当前循环的开始时间
    # print(key+':'+value)
    worksheet = workbook.add_sheet(key)  # 创建一个worksheet
    start_data = page.get_page(url=value, coding='GB2312')  # 确定省份的起始页码
    head = page.get_head(data=start_data)  # 确定省份页的表头
    ncolumn = len(head)  # 计算一共有多少列
    for i in range(1, ncolumn):
        worksheet.write(0, i, label=head[i])  # 把表头写入到Excel中
    for pages in range(page.get_numdata(data=start_data)):
        url_1 = value[:-5] + str(pages + 1) + '.htm'
        print('正在查询第', str(pages + 1), '页')
        page_data = page.get_page(url=url_1, coding='GB2312')  # 获取当前页面数据
        num_data = page.get_numdata(data=page_data)  # 获取当前页面的页数
        rice_data = rdata.get_data(soup=page_data)  # 获取当前页面35行品种数据,就是单元格的数量
        n = int(len(rice_data) / 7)  # 列表中的数据是每一行有7列,页面的总行数=总单元格数/7
        for x in range(1, n + 1):  # 写入excel
            z_data = page.get_page(url=rice_data[(x - 1) * 7 + 2], coding='GB2312')
            pz_data = page.get_detailed_data(data=z_data)
            dedata = page.get_dedata(de_data=pz_data)
            row = pages * 35 + x  # 第**行
            for y in range(1, ncolumn + 1):
                if y - 1 == 2:  # 判断是否是第3列,如果是则将网址改变成超链接的格式。
                    rd = rice_data[(x - 1) * 7 + y - 1]  # 单元格数据
                    colum = head[y - 1]  # 第**列
                    worksheet.write(row, y - 1, label=xlwt.Formula(
                        "HYPERLINK" + '("' + rd + '";"' + rd + '")'))  # 参数对应 行, 列, 值
                    print("{0:^6}\t{1:{2}<12}".format(str(pages * 35 + x), colum, chr(12288)),rd)
                elif y - 1 > 6:  # 当单元格的列数在第7行之后,需要获取 具体品种 网址内品种数据
                    rd = dedata[y - 8]  # 单元格数据
                    colum = head[y - 1]  # 第**列
                    worksheet.write(row, y - 1, label=rd)
                    print("{0:^6}\t{1:{2}<12}".format(row, head[y - 1], chr(12288)),rd)
                else:
                    rd = rice_data[(x - 1) * 7 + y - 1]  # 单元格数据
                    colum = head[y - 1]  # 第**列
                    worksheet.write(row, y - 1, label=rd)  # 参数对应 行, 列, 值
                    print("{0:^6}\t{1:{2}<12}".format(row, head[y - 1], chr(12288)),rd)
    endtime = datetime.datetime.now()  # 计算当前循环的结束时间
    print(key, '的品种数据写入完成', '耗时:', (endtime - starttime).seconds, '秒')
    print('等待5秒后继续下一个省份')
    time.sleep(5)
dirs = os.getcwd() # 获取页面的
filename = dirs + '\\品种数据.xls'
workbook.save(filename)  # 保存
print('保存完毕,文件路径为:', filename)
time.sleep(2)

实际获取的数据如下:

import sys; print('Python %s on %s' % (sys.version, sys.platform))
sys.path.extend(['C:\\Python\\PycharmProjects', 'C:/Python/PycharmProjects'])
PyDev console: starting.
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 02:47:15) [MSC v.1900 32 bit (Intel)] on win3
请求数据
正在查询第 11   	序号           1
  1   	品种名称         韵两优827
  1   	网址           http://www.ricedata.cn/variety/varis/618369.htm
  1   	亲本来源("×"前为母本) 韵2013S×R827
  1   	类型           籼型两系杂交稻
  1   	原产地/选育单位     袁隆平农业高科技股份有限公司等
  1   	审定编号         国审稻20186143
  1   	全生育期         116.0
  1   	株高           107.6
  1   	穗长           23.6
  1   	每亩有效穗        18.5
  1   	每穗总粒数        163.3
  1   	结实率          81.4
  1   	千粒重          23.4
  1   	整精米率         66.4
  1   	垩白粒率         15
  1   	垩白度          3.7
  1   	直链淀粉含量       15.6
  1   	胶稠度          71
  1   	长宽比          3.1