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
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
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
请求数据
正在查询第 1 页
1 序号 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