lottery_scraper.php

12.32 KB
03/07/2025 14:26
PHP
lottery_scraper.php
<?php
/**
 * Lottery Statistics Scraper for MyHora
 * อ่านข้อมูลสถิติหวยจาก MyHora และ parse ข้อมูลออกมา
 */

class LotteryScraper
{
    /**
     * @var string
     */
    private $baseUrl = 'https://www.thairath.co.th/lottery/statistics';
    /**
     * @var string
     */
    private $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
    /**
     * @var string
     */
    private $cacheFile = 'lottery_cache.json';
    /**
     * @var int
     */
    private $cacheExpiry = 3600; // 1 ชั่วโมง

    /**
     * อ่านข้อมูลสถิติหวยจาก MyHora
     */
    public function scrapeLotteryStats($month = '09', $year = '10', $round = '0')
    {
        $results = [];
        $today = date('Y-m-d');
        try {
            // 1. อ่านงวดปัจจุบันจากหน้าแรก Thairath
            $latest = $this->scrapeThairathLatest();
            if ($latest && $latest['prize1'] && $latest['date'] && $latest['date'] <= $today) {
                $results[] = $latest;
            }
            // 2. อ่านงวดย้อนหลัง (จากหน้าสถิติจริง)
            $html = $this->fetchUrl($this->baseUrl);
            $history = $this->parseLotteryStats($html);
            if (isset($history['data']) && is_array($history['data'])) {
                foreach ($history['data'] as $item) {
                    // ไม่ซ้ำกับงวดปัจจุบัน และไม่ใช่อนาคต
                    if (
                        (!isset($latest['prize1']) || $item['prize1'] !== $latest['prize1']) &&
                        isset($item['date']) && $item['date'] <= $today
                    ) {
                        $results[] = $item;
                    }
                }
            }
        } catch (Exception $e) {
            // ถ้า scrape ไม่สำเร็จ ให้ return ข้อมูลว่างและ error
            return [
                'success' => false,
                'error' => 'Scrape failed: '.$e->getMessage(),
                'data' => [],
                'timestamp' => time(),
                'source' => 'Thairath'
            ];
        }
        // บันทึก cache เฉพาะเมื่อ scrape สำเร็จ
        $this->saveCache([
            'success' => true,
            'source' => 'Thairath',
            'total_records' => count($results),
            'data' => $results,
            'timestamp' => time()
        ]);
        return [
            'success' => true,
            'source' => 'Thairath',
            'total_records' => count($results),
            'data' => $results,
            'timestamp' => time()
        ];
    }

    /**
     * อ่านงวดปัจจุบันจากหน้าแรก Thairath
     */
    private function scrapeThairathLatest()
    {
        $url = 'https://www.thairath.co.th/lottery';
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_USERAGENT => $this->userAgent,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => false
        ]);
        $html = curl_exec($ch);
        curl_close($ch);
        if (!$html) {
            return null;
        }
        // ใช้ DOMDocument + XPath ดึง <p> 6 ตัวแรกใน <div class="__Result_full ...">
        $prize1 = null;
        $dom = new DOMDocument();
        @$dom->loadHTML($html, LIBXML_NOERROR | LIBXML_NOWARNING);
        $xpath = new DOMXPath($dom);
        $divs = $xpath->query('//div[contains(@class,"__Result_full")]');
        if ($divs->length > 0) {
            $pNodes = $xpath->query('.//p', $divs->item(0));
            $digits = [];
            foreach ($pNodes as $p) {
                $digits[] = trim($p->textContent);
                if (count($digits) === 6) {
                    break;
                }

            }
            if (count($digits) === 6) {
                $prize1 = implode('', $digits);
            }
        }
        // ดึงวันที่
        $thai_date = null;
        if (preg_match('/<span[^>]+__title_date[^>]*as=["\']h1["\'][^>]*>([^<]+)<\/span>/u', $html, $m2)) {
            $raw = trim($m2[1]);
            if (preg_match('/งวดประจำวันที่\s*(.+)/u', $raw, $m3)) {
                $thai_date = trim($m3[1]);
            } else {
                $thai_date = $raw;
            }
            // ลบวันในสัปดาห์ออก (ถ้ามี)
            $thai_date = preg_replace('/^(จันทร์|อังคาร|พุธ|พฤหัสบดี|ศุกร์|เสาร์|อาทิตย์)\s*/u', '', $thai_date);
        }
        $date = null;
        if ($thai_date) {
            $date = $this->convertThaiDate($thai_date);
        }
        return [
            'date' => $date,
            'prize1' => $prize1
        ];
    }

    /**
     * ดึงข้อมูลจาก URL ด้วย cURL
     */
    private function fetchUrl($url)
    {
        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_USERAGENT => $this->userAgent,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_HTTPHEADER => [
                'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                'Accept-Language: th-TH,th;q=0.9,en;q=0.8',
                'Accept-Encoding: identity',
                'Connection: keep-alive',
                'Upgrade-Insecure-Requests: 1'
            ]
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200 || !$response) {
            throw new Exception('Fetch failed: HTTP '.$httpCode);
        }
        return $response;
    }

    /**
     * Parse HTML และดึงข้อมูลรางวัลที่ 1 จากไทยรัฐ (robust)
     */
    private function parseLotteryStats($html)
    {
        $dom = new DOMDocument();
        @$dom->loadHTML($html, LIBXML_NOERROR | LIBXML_NOWARNING);
        $xpath = new DOMXPath($dom);

        $results = [];
        // วนลูปทุก table
        $tables = $xpath->query('//table');
        foreach ($tables as $table) {
            // หา td ที่เป็นวันที่
            $dateCell = $xpath->query('.//td[contains(@class, "td-date")]', $table);
            // หา td ที่เป็นรางวัลที่ 1
            $prize1Cell = $xpath->query('.//td[contains(@class, "td-prizeone")]', $table);
            if ($dateCell->length > 0 && $prize1Cell->length > 0) {
                $date_th = trim($dateCell->item(0)->textContent);
                // ตัด <span> ออก เหลือแต่ตัวเลข
                $prize1Node = $prize1Cell->item(0);
                $prize1Text = '';
                foreach ($prize1Node->childNodes as $child) {
                    if ($child->nodeType === XML_TEXT_NODE) {
                        $prize1Text .= $child->nodeValue;
                    }
                }
                $prize1Text = trim($prize1Text);
                // ดึงเฉพาะตัวเลขรางวัลที่ 1 (6 หลัก)
                if (preg_match('/(\d{6})/', $prize1Text, $matches)) {
                    $prize1 = $matches[1];
                    $engDate = $this->convertThaiDate($date_th);
                    $results[] = [
                        'date' => $engDate,
                        'prize1' => $prize1
                    ];
                }
            }
        }
        return [
            'success' => true,
            'source' => 'Thairath',
            'total_records' => count($results),
            'data' => $results,
            'timestamp' => time()
        ];
    }

    /**
     * แปลงวันที่ไทยเป็นภาษาอังกฤษ
     */
    private function convertThaiDate($thaiDate)
    {
        // ตัดวันในสัปดาห์ออก (ถ้ามี)
        $thaiDate = preg_replace('/^(จันทร์|อังคาร|พุธ|พฤหัสบดี|ศุกร์|เสาร์|อาทิตย์)\s*/u', '', trim($thaiDate));
        $thaiMonths = [
            'ม.ค.' => '01', 'ก.พ.' => '02', 'มี.ค.' => '03', 'เม.ย.' => '04',
            'พ.ค.' => '05', 'มิ.ย.' => '06', 'ก.ค.' => '07', 'ส.ค.' => '08',
            'ก.ย.' => '09', 'ต.ค.' => '10', 'พ.ย.' => '11', 'ธ.ค.' => '12',
            'มกราคม' => '01', 'กุมภาพันธ์' => '02', 'มีนาคม' => '03', 'เมษายน' => '04',
            'พฤษภาคม' => '05', 'มิถุนายน' => '06', 'กรกฎาคม' => '07', 'สิงหาคม' => '08',
            'กันยายน' => '09', 'ตุลาคม' => '10', 'พฤศจิกายน' => '11', 'ธันวาคม' => '12'
        ];
        if (preg_match('/(\d{1,2})\s+([\p{Thai}.]+)\s+(\d{2,4})/u', $thaiDate, $matches)) {
            $day = str_pad($matches[1], 2, '0', STR_PAD_LEFT);
            $month = $thaiMonths[$matches[2]] ?? '01';
            $year = $matches[3];
            if (strlen($year) == 2) {
                $year = (2500 + intval($year)) - 543;
            } else if (strlen($year) == 4) {
                $year = intval($year) - 543;
            }
            return $year.'-'.$month.'-'.$day;
        }
        return date('Y-m-d');
    }

    /**
     * ดึงข้อมูลจาก cache
     */
    private function getCachedData()
    {
        if (!file_exists($this->cacheFile)) {
            return false;
        }

        $cacheData = json_decode(file_get_contents($this->cacheFile), true);

        if (!$cacheData || !isset($cacheData['timestamp'])) {
            return false;
        }

        // ตรวจสอบว่า cache หมดอายุหรือยัง
        if (time() - $cacheData['timestamp'] > $this->cacheExpiry) {
            return false;
        }

        return $cacheData;
    }

    /**
     * บันทึกข้อมูลลง cache
     */
    private function saveCache($data)
    {
        file_put_contents($this->cacheFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
    }

    /**
     * ส่งข้อมูลเป็น JSON
     */
    public function getJsonResponse($month = '09', $year = '10', $round = '0')
    {
        header('Content-Type: application/json; charset=utf-8');
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, POST');
        header('Access-Control-Allow-Headers: Content-Type');

        $stats = $this->scrapeLotteryStats($month, $year, $round);

        $response = [
            'success' => !isset($stats['error']),
            'timestamp' => time(),
            'stats' => $stats
        ];

        if (isset($stats['error'])) {
            $response['error'] = $stats['error'];
        }

        echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }
}

// ใช้งาน
if (isset($_GET['action']) && $_GET['action'] === 'scrape') {
    $scraper = new LotteryScraper();

    $month = $_GET['month'] ?? '09';
    $year = $_GET['year'] ?? '10';
    $round = $_GET['round'] ?? '0';

    $scraper->getJsonResponse($month, $year, $round);
    exit;
}

// ตัวอย่างการใช้งาน
if (basename(__FILE__) === basename($_SERVER['SCRIPT_NAME'])) {
    echo "<h1>🎯 Lottery Statistics Scraper</h1>";
    echo "<p>ใช้ URL: <code>?action=scrape&month=09&year=10&round=0</code></p>";

    if (isset($_GET['test'])) {
        $scraper = new LotteryScraper();
        $stats = $scraper->scrapeLotteryStats();

        echo "<h2>ผลการทดสอบ:</h2>";
        echo "<pre>".json_encode($stats, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)."</pre>";
    }
}