中国银行汇率查询:https://srh.bankofchina.com/search/whpj/search_cn.jsp
1.参数:
字段 | 描述 |
---|
nothing | 开始日期,例如2023-10-23 |
erectDate | 结束日期,例如2023-10-25 |
pjname | 币种名称,例如“欧元” |
page | 页码,默认1 |
2.封装类
<?php
class BocRate {
private $settings = array(
'used' => true,
'url' => 'https://srh.bankofchina.com/search/whpj/search_cn.jsp',
'post_string' => 'nothing=%s&erectDate=%s&pjname=%s&page=%s',
'money_code' => array('EUR' => '1326', 'USD' => '1316', 'GBP' => '1314','HKD' => '1315','RUB' => '1843','BRL' => '3253'),
'money_name' => array('EUR'=>'欧元', 'USD'=>'美元', 'GBP'=>'英镑','HKD'=>'港币','RUB'=>'卢布','BRL'=>'巴西里亚尔'),
'count_preg' => '/var m_nRecordCount = (.*);/',
'size_preg' => '/var m_nPageSize = (.*);/',
'table_preg' => '/<table cellpadding="0" cellspacing="0" width="100%" align="left">
<tr>
([\s\S]*?)<\/table>/', //别乱排版,不然会匹配不到
'table_header' => array('货币名称', '现汇买入价', '现钞买入价', '现汇卖出价', '现钞卖出价', '中行折算价', '发布时间'),
'header_var' => array('currency', 'rate_po', 'rate_cash', 'rate_average', 'rate_norm', 'boc', 'pub_time'),
'value_preg' => '/<td>(.*?)<\/td>/s',
'charset' => 'GB2312'
);
private function composeData($post_string, $rate_date, $pjname, $page=1) {
return(sprintf($post_string, urlencode($rate_date), urlencode($rate_date), urlencode($pjname), urlencode($page)));
}
public function getBocRate(&$result,$rate_date, $from, $to='RMB') {
$result['from'] = $from;
$result['to'] = $to;
$post_data = $this->composeData($this->settings['post_string'], $rate_date, $this->settings['money_name'][$from]);
$data = $this->curlPost($this->settings['url'],$post_data);
if (false === $data) {
$result['error'] = 'access webpage error, url=' . $this->settings['url'] . '<>post=' . $post_data;
return(false);
}
$page_no = 1;
$line_no = 1;
if (preg_match($this->settings['count_preg'], $data, $record_count)) { //查找记录的总条数
if (is_numeric($record_count[1]) && $record_count[1] > 0) { //是正数
if (preg_match($this->settings['size_preg'], $data, $page_size)) { //查找每页的条数
if (is_numeric($page_size[1]) && ($page_size[1] > 0)) { //是正数
$page_no = intval(($record_count[1] - 1) / $page_size[1] + 1); //计算一共有多少页
$line_no = $record_count[1] - ($page_no - 1) * $page_size[1]; //最后一条所在的行数
}
}
}
}
if (1 != $page_no) { //要抓的汇率不在第一页
$post_data = $this->composeData($this->settings['post_string'], $rate_date, $this->settings['money_name'][$from], $page_no);
$data2 = $this->curlPost($this->settings['url'],$post_data);
if ($data2) { //成功取到网页
$data = $data2;
unset($data2);
}else {
$line_no = 1; //没有抓到最后一页,那就还用抓到页的第一行
}
}
if (!preg_match($this->settings['table_preg'], $data, $table)) { //未找到汇率表
$result['error'] = 'cannot find table, source code=' . $data;
return(false);
}
$rows = explode('</tr>', $table[1]); //对表格分行,只分到需要的行
if (count($rows) < $line_no+1) { //行数不对
$result['error'] = 'cannot find encough rows, source code=' . $table[1];
return(false);
}
$table_header = $this->settings['table_header'];
preg_match_all('/<th>(.*?)<\/th>/s',$rows[0], $head);
$head = $head[1];
$header_count = count($table_header);
if (count($head)< $header_count) { //表头不对
$result['error'] = 'table header error, source code=' . $rows[0];
return(false);
}
for ($i=0; $i<$header_count; $i++) { //核对表头
if (false === strpos($head[$i], $table_header[$i])) { //表头不匹配
$result['error'] = 'table header error, source code=' . $rows[0];
return(false);
}
}
if (!preg_match_all($this->settings['value_preg'], $rows[$line_no], $columns)) { //行不匹配
$result['error'] = 'column mismatch, source code=' . $rows[$line_no];
return(false);
}
$columns = $columns[1];
$count = count($columns);
if ($count < $header_count) { //抓取到的值少于表头的列数,出错
$result['error'] = 'column mismatch, source code=' . $rows[$line_no];
return(false);
}
for($i=0; $i<$header_count; $i++) {
$result[$this->settings['header_var'][$i]] = trim($columns[$i]);
}
$money_name = $this->settings['money_name'][$from];
if ($result['currency'] != $money_name) {//抓取到的币值名称不匹配
$result['error'] = 'money name mismatch, ' . print_r($result, true);
return false;
}
///特殊处理BRL,
if($money_name == '巴西里亚尔'){
$result['rate_average'] = 0;
$result['rate_po'] = trim($columns[5]);
}
return true;
}
public function curlPost($url, $post = array(), $timeout = 60){
if (empty($url)) {
return '';
}
$ch = curl_init(); //初始化
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);//只需要设置一个秒的数量就可以
curl_setopt($ch, CURLOPT_POST, 1);
if(is_array($post)){
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
}else{
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
if(stripos($url,'https') === 0){
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
}
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
?>
3.使用方式
require_once 'BocRate.php';
function getRate($from){
$date = date("Y-m-d");
$rate = new BocRate();
$data = array();
$rate->getBocRate($data,$date,$from,'RMB');
return $data;
}
$money_name = array('EUR'=>'欧元', 'USD'=>'美元', 'GBP'=>'英镑', 'HKD'=>'港币','RUB'=>'卢布');
foreach ($money_name as $key=>$item) {
$info = getRate($key);
var_dump( $info);
}
4.效果
array(9) {
["from"] => string(3) "EUR"
["to"] => string(3) "RMB"
["currency"] => string(6) "欧元"
["rate_po"] => string(6) "774.43"
["rate_cash"] => string(6) "768.59"
["rate_average"] => string(6) "779.85"
["rate_norm"] => string(6) "781.87"
["boc"] => string(6) "761.98"
["pub_time"] => string(19) "2023.10.31 00:00:05"
}
新浪汇率查询:http://biz.finance.sina.com.cn/forex/forex.php?startdate=2023-10-31&enddate=2023-12-01&money_code=HKD&type=0
1.参数
字段 | 描述 |
---|
startdate | 开始日期,例如2023-10-23 |
enddate | 结束日期,例如2023-10-25 |
money_code | 币种,例如“EUR” |
type | 页码,默认0 |
2.封装类
<?php
class SinaRate{
private $settings = array(
'url' => 'http://biz.finance.sina.com.cn/forex/',
'get_string' => 'forex.php?startdate=%s&enddate=%s&money_code=%s&type=0',
'money_code' => array('EUR'=>'EUR', 'USD'=>'USD', 'GBP'=>'GBP','HKD'=>'HKD','RUB'=>'RUB'),
'money_name' => array('EUR'=>'欧元', 'USD'=>'美元', 'GBP'=>'英镑', 'HKD'=>'港币','RUB'=>'卢布'),
'page_preg' => "caption='%s兑人民币日线图'",
'table_preg' => '/<table class="list_table">([\s\S]*?)<\/table>/',
'row_count' => 2,
'table_header' => array('日期', '汇买价(元)', '钞买价(元)', '钞卖价/汇卖价', '中间价'),
'header_var' => array('pub_time', 'rate_po', 'rate_cash', 'rate_average', 'rate_convert'),
'pub_time_index'=> 0,
'value_preg' => '/<tr >[\s\S]*?<td >(.*?)<\/td>[\s\S]*?<td >(.*?)<\/td>[\s\S]*?<td >(.*?)<\/td>[\s\S]*?<td >(.*?)<\/td>[\s\S]*?<td >(.*?)<\/td>/',
'value_omit' => array('rate_norm' => 'rate_average'),
'charset' => 'GB2312'
);
private function composeData($get_string, $rate_date, $pjname) {
return(sprintf($get_string, urlencode($rate_date), urlencode($rate_date), urlencode($this->settings['money_code'][$pjname])));
}
public function getSinaRate(&$result,$rate_date, $from, $to='RMB') {
$result['from'] = $from;
$result['to'] = $to;
$result['source'] = $this->settings['class'];
$get_data = $this->composeData($this->settings['get_string'], $rate_date, $from);
$data = file_get_contents($this->settings['url'] . $get_data);
if (false === $data) {
$result['error'] = 'access webpage error, url=' . $this->settings['url'] . $get_data;
return(false);
}
$page_sign = sprintf($this->settings['page_preg'], $this->settings['money_name'][$from]);
$page_sign = iconv('UTF-8', $this->settings['charset'], $page_sign);
if (false === strpos($data, $page_sign)) { //页面不匹配
$result['error'] = 'page mismatch, source code=' . $data;
return(false);
}
if (!preg_match($this->settings['table_preg'], $data, $table)) { //未找到汇率表
$result['error'] = 'cannot find table, source code=' . $data;
return(false);
}
$rows = explode('</tr>', $table[1]); //对表格分行
if (count($rows) != $this->settings['row_count']+1) { //表格的行数不对
$result['error'] = 'wrong row count, source code=' . $table[1];
return(false);
}
$table_header = $this->settings['table_header'];
$head = explode('</td>', $rows[0]); //处理表头
$header_count = count($table_header);
if (count($head) < $header_count) { //表头不对
$result['error'] = 'table header error, source code=' . $rows[0];
return(false);
}
for ($i=0; $i<$header_count; $i++) { //核对表头
if (false === strpos($head[$i], iconv('UTF-8', $this->settings['charset'], $table_header[$i]))) { //表头不匹配
$result['error'] = 'table header error, source code=' . $rows[0];
return(false);
}
}
if (!preg_match_all($this->settings['value_preg'], $rows[1], $columns)) { //行不匹配
$result['error'] = 'column mismatch, source code=' . $rows[1];
return(false);
}
$count = count($columns);
if ($count <= $header_count) { //抓取到的值少于表头的列数,出错
$result['error'] = 'column mismatch, source code=' . $rows[$line_no];
return(false);
}
for($i=1; $i<$header_count+1; $i++) {
$result[$this->settings['header_var'][$i-1]] = $columns[$i][0];
}
if ($result['pub_time'] != $rate_date) { //日期不匹配
$result['error'] = "date mismatch, wanted date: $rate_date, got date: " . $result['pub_time'];
return(false);
}
$omits = $this->settings['value_omit'];
foreach ($omits as $key => $value) {
$result[$key] = $result[$value];
}
return(true);
}
}
3.使用方式
require_once 'SinaRate.php';
function getRate($from){
$date = date("Y-m-d");
$rate = new SinaRate();
$data = array();
$rate->getSinaRate($data,$date,$from,'RMB');
return $data;
}
$money_name = array('EUR'=>'欧元', 'USD'=>'美元', 'GBP'=>'英镑', 'HKD'=>'港币','RUB'=>'卢布');
foreach ($money_name as $key=>$item) {
$info = getRate($key);
var_dump($info);
}
4.效果
array(8) {
["from"] => string(3) "EUR"
["to"] => string(3) "RMB"
["pub_time"] => string(10) "2023-10-31"
["rate_po"] => string(8) "773.7800"
["rate_cash"] => string(8) "767.9500"
["rate_average"] => string(8) "779.2000"
["rate_convert"] => string(8) "764.8000"
["rate_norm"] => string(8) "779.2000"
}