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

利用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

你可能感兴趣的:(python)