Skip to content

Commit

Permalink
Wip
Browse files Browse the repository at this point in the history
  • Loading branch information
shimomo committed Feb 6, 2025
1 parent 01659a3 commit 938905c
Show file tree
Hide file tree
Showing 14 changed files with 615 additions and 3 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2020 shimomo
Copyright (c) 2025 shimomo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
22 changes: 22 additions & 0 deletions src/Exceptions/AccessoryNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Boatrace\Venture\Project\Exceptions;

/**
* @author shimomo
*/
class AccessoryNotFoundException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param \Throwable|null $previous
* @return void
*/
public function __construct(string $message, int $code = 404, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
13 changes: 13 additions & 0 deletions src/MainAccessory.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,17 @@ public function comments(int $stadiumId, int $raceNumber, ?string $date = null):
sprintf('Stadium%02d', $stadiumId)
)->comments($raceNumber, $date))->recursive();
}

/**
* @param int $stadiumId
* @param int $raceNumber
* @param string|null $date
* @return \Illuminate\Support\Collection
*/
public function forecasts(int $stadiumId, int $raceNumber, ?string $date = null): Collection
{
return collect(Accessory::getInstance(
sprintf('Stadium%02d', $stadiumId)
)->forecasts($raceNumber, $date))->recursive();
}
}
157 changes: 157 additions & 0 deletions src/Stadiums/Stadium03.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

namespace Boatrace\Venture\Project\Stadiums;

use Boatrace\Venture\Project\Exceptions\AccessoryNotFoundException;
use Carbon\CarbonImmutable as Carbon;
use Symfony\Component\DomCrawler\Crawler;

/**
* @author shimomo
*/
Expand All @@ -28,4 +32,157 @@ public function comments(int $raceNumber, ?string $date = null): array
{
return [];
}

/**
* @param int $raceNumber
* @param string|null $date
* @return array
*/
public function forecasts(int $raceNumber, ?string $date = null): array
{
$date = Carbon::parse($date ?? 'today')->format('Ymd');

return array_merge(...[
$this->fetchYesterdayForecasts($raceNumber, $date),
$this->fetchTodayForecasts($raceNumber, $date),
]);
}

/**
* @param int $raceNumber
* @param string $date
* @return array
*/
protected function fetchYesterdayForecasts(int $raceNumber, string $date): array
{
$baseUrl = 'https://boatrace-edogawa.com';
$crawlerFormat = '%s/modules/yosou/zenjitsu.php?day=%s&race=%d';
$crawlerUrl = sprintf($crawlerFormat, $baseUrl, $date, $raceNumber);
$crawler = $this->httpBrowser->request('GET', $crawlerUrl);
$forecasts = $this->filterByKeys($crawler, [
'#padtop > div',
'.jishindo > b',
]);

foreach ($forecasts as $key => $value) {
if (empty($value)) {
throw new AccessoryNotFoundException(
'No data found for key \'' . $key . '\' at \'' . $crawlerUrl . '\'.'
);
}
}

$focus = [];
$focusIndex = 0;
$crawler->filter('img')->each(function ($node) use (&$focus, &$focusIndex) {
if (preg_match('/\/images\/icon_num([^\/]+)\.png/u', $node->attr('src'), $matches)) {
$focus[$focusIndex] ??= '';
$focus[$focusIndex] .= $matches[1];
return;
}

if (preg_match('/\/images\/equal\.png/u', $node->attr('src'), $matches)) {
$focus[$focusIndex] ??= '';
$focus[$focusIndex] .= '=';
return;
}

if (preg_match('/\/images\/fifun\.png/u', $node->attr('src'), $matches)) {
$focus[$focusIndex] ??= '';
$focus[$focusIndex] .= '-';
return;
}

$focusIndex++;
});

$reporterYesterdayCommentLabel = '記者予想 前日コメント';
$reporterYesterdayFocusLabel = '記者予想 前日フォーカス';
$reporterYesterdayFocusTrifectaLabel = '記者予想 前日フォーカス 3連単';
$reporterYesterdayFocusExactaLabel = '記者予想 前日フォーカス 2連単';
$reporterYesterdayReliabilityLabel = '記者予想 前日信頼度';

$reporterYesterdayComment = $this->normalize($forecasts['#padtop > div'][0]);
$reporterYesterdayFocus = $this->normalizeArray($this->filterFocusByLength($focus, 5));
$reporterYesterdayFocusTrifecta = $this->normalizeArray($this->filterFocusByLength($focus, 5));
$reporterYesterdayFocusExacta = $this->normalizeArray($this->filterFocusByLength($focus, 3));
$reporterYesterdayReliability = rtrim($this->normalize($forecasts['.jishindo > b'][0]), '%') . '%';

if (empty($reporterYesterdayFocusExacta) || empty($reporterYesterdayFocusTrifecta)) {
throw new AccessoryNotFoundException(
'No data found for key \'img\' at \'' . $crawlerUrl . '\'.'
);
}

return [
'reporter_yesterday_comment_label' => $reporterYesterdayCommentLabel,
'reporter_yesterday_comment' => $reporterYesterdayComment,
'reporter_yesterday_focus_label' => $reporterYesterdayFocusLabel,
'reporter_yesterday_focus' => $reporterYesterdayFocus,
'reporter_yesterday_focus_trifecta_label' => $reporterYesterdayFocusTrifectaLabel,
'reporter_yesterday_focus_trifecta' => $reporterYesterdayFocusTrifecta,
'reporter_yesterday_focus_exacta_label' => $reporterYesterdayFocusExactaLabel,
'reporter_yesterday_focus_exacta' => $reporterYesterdayFocusExacta,
'reporter_yesterday_reliability_label' => $reporterYesterdayReliabilityLabel,
'reporter_yesterday_reliability' => $reporterYesterdayReliability,
];
}

/**
* @param int $raceNumber
* @param string $date
* @return array
*/
protected function fetchTodayForecasts(int $raceNumber, string $date): array
{
$baseUrl = 'https://boatrace-edogawa.com';
$crawlerFormat = '%s/modules/yosou/cyokuzen.php?day=%s&race=%d';
$crawlerUrl = sprintf($crawlerFormat, $baseUrl, $date, $raceNumber);
$this->httpBrowser->request('GET', $crawlerUrl);
$response = $this->httpBrowser->getResponse();
$content = mb_convert_encoding($response->getContent(), 'EUC-JP', 'UTF-8');
$crawler = new Crawler($content);

$forecasts = $this->filterByIdPrefixes($crawler, [
'#overflowhidden;letter-spacing:0px;',
]);

$pattern = '/\d+[^\d]\d+[^\d]\d+/u';
$subject = $forecasts['#overflowhidden;letter-spacing:0px;'][0];

if (($comments = preg_split($pattern, $subject)) === false) {
throw new AccessoryNotFoundException(
'No data found for key \'#overflowhidden;letter-spacing:0px;\' at \'' . $crawlerUrl . '\'.'
);
}

if (! preg_match_all($pattern, $subject, $matches)) {
throw new AccessoryNotFoundException(
'No data found for key \'#overflowhidden;letter-spacing:0px;\' at \'' . $crawlerUrl . '\'.'
);
}

$reporterTodayCommentLabel = '記者予想 当日コメント';
$reporterTodayFocusLabel = '記者予想 当日フォーカス';

$reporterTodayComment = $this->normalize($comments[0]);
$reporterTodayFocus = $this->normalizeArray($matches[0]);

return [
'reporter_today_comment_label' => $reporterTodayCommentLabel,
'reporter_today_comment' => $reporterTodayComment,
'reporter_today_focus_label' => $reporterTodayFocusLabel,
'reporter_today_focus' => $reporterTodayFocus,
];
}

/**
* @param array $focus
* @param int $length
* @return array
*/
protected function filterFocusByLength(array $focus, int $length): array
{
return array_values(array_filter($focus, fn($value) => strlen($value) === $length));
}
}
49 changes: 49 additions & 0 deletions src/Stadiums/Stadium05.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Boatrace\Venture\Project\Stadiums;

use Boatrace\Venture\Project\Exceptions\AccessoryNotFoundException;
use Carbon\CarbonImmutable as Carbon;

/**
Expand Down Expand Up @@ -53,4 +54,52 @@ public function comments(int $raceNumber, ?string $date = null): array
{
return [];
}

/**
* @param int $raceNumber
* @param string|null $date
* @return array
*/
public function forecasts(int $raceNumber, ?string $date = null): array
{
$date = Carbon::parse($date ?? 'today')->format('Ymd');
$baseUrl = 'https://boatrace-tamagawa.com';
$crawlerFormat = '%s/modules/yosou/syussou.php?day=%s&race=%d&jo=05';
$crawlerUrl = sprintf($crawlerFormat, $baseUrl, $date, $raceNumber);
$crawler = $this->httpBrowser->request('GET', $crawlerUrl);
$forecasts = $this->filterByKeys($crawler, [
'.z_sinnyu',
'.z_focus_2ren > .focus_list > li',
'.z_focus_3ren > .focus_list > li',
'.z_comment',
'.j_sinnyu',
'.j_focus > .focus_list > li',
'.j_reliability',
]);

foreach ($forecasts as $key => $value) {
if (empty($value)) {
throw new AccessoryNotFoundException(
'No data found for key \'' . $key . '\' at \'' . $crawlerUrl . '\'.'
);
}
}

return [
'reporter_yesterday_course_label' => '記者予想 前日コース',
'reporter_yesterday_course' => $this->normalize($forecasts['.z_sinnyu'][0]),
'reporter_yesterday_focus_exacta_label' => '記者予想 前日フォーカス 2連単',
'reporter_yesterday_focus_exacta' => $this->normalizeArray($forecasts['.z_focus_2ren > .focus_list > li']),
'reporter_yesterday_focus_trifecta_label' => '記者予想 前日フォーカス 3連単',
'reporter_yesterday_focus_trifecta' => $this->normalizeArray($forecasts['.z_focus_3ren > .focus_list > li']),
'reporter_yesterday_comment_label' => '記者予想 前日コメント',
'reporter_yesterday_comment' => $this->normalize($forecasts['.z_comment'][0]),
'jlc_yesterday_course_label' => 'JLC予想 前日コース',
'jlc_yesterday_course' => $this->normalize($forecasts['.j_sinnyu'][0]),
'jlc_yesterday_focus_label' => 'JLC予想 前日フォーカス',
'jlc_yesterday_focus' => $this->normalizeArray($forecasts['.j_focus > .focus_list > li']),
'jlc_yesterday_reliability_label' => 'JLC予想 前日信頼度',
'jlc_yesterday_reliability' => $this->normalize($forecasts['.j_reliability'][0]),
];
}
}
44 changes: 44 additions & 0 deletions src/Stadiums/Stadium11.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,48 @@ public function comments(int $raceNumber, ?string $date = null): array
{
return [];
}

/**
* @param int $raceNumber
* @param string|null $date
* @return array
*/
public function forecasts(int $raceNumber, ?string $date = null): array
{
$date = Carbon::parse($date ?? 'today')->format('Ymd');
$baseUrl = 'https://www.boatrace-biwako.jp';
$crawlerFormat = '%s/modules/yosou/syussou.php?day=%s&race=%d';
$crawlerUrl = sprintf($crawlerFormat, $baseUrl, $date, $raceNumber);
$crawler = $this->httpBrowser->request('GET', $crawlerUrl);
$forecasts = $this->filterByKeys($crawler, [
'.sinnyu-div > ul > .num',
'.comment-div',
'.focus > li',
]);

foreach ($forecasts as $key => $value) {
if (empty($value)) {
throw new AccessoryNotFoundException(
'No data found for key \'' . $key . '\' at \'' . $crawlerUrl . '\'.'
);
}
}

$reporterYesterdayCourseLabel = '記者予想 前日コース';
$reporterYesterdayFocusLabel = '記者予想 前日フォーカス';
$reporterYesterdayCommentLabel = '記者予想 前日コメント';

$reporterYesterdayCourse = $this->normalize(implode($forecasts['.sinnyu-div > ul > .num']));
$reporterYesterdayFocus = $this->normalizeArray($forecasts['.focus > li']);
$reporterYesterdayComment = $this->normalize($forecasts['.comment-div'][0]);

return [
'reporter_yesterday_course_label' => $reporterYesterdayCourseLabel,
'reporter_yesterday_course' => $reporterYesterdayCourse,
'reporter_yesterday_focus_label' => $reporterYesterdayFocusLabel,
'reporter_yesterday_focus' => $reporterYesterdayFocus,
'reporter_yesterday_comment_label' => $reporterYesterdayCommentLabel,
'reporter_yesterday_comment' => $reporterYesterdayComment,
];
}
}
Loading

0 comments on commit 938905c

Please sign in to comment.