| Server IP : 173.209.174.21 / Your IP : 216.73.216.89 Web Server : Apache/2.4.58 (Ubuntu) System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : nodor ( 1000) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/nykoinc/export/ |
Upload File : |
<?php
/**
* Warrant Search scraper → CSV exporter
*
* Usage (from CLI):
* php warrant_export.php
*
* This will create warrants_export.csv in the same directory.
*/
ini_set('memory_limit', '512M');
set_time_limit(0);
$baseUrl = "https://doc.wa.gov/records/incarcerated-data-search/warrant-search";
$outputCsv = __DIR__ . "/warrants_export.csv";
$userAgent = "Mozilla/5.0 (compatible; WCFS-scraper/1.0; +you@example.com)";
// -------------- HTTP FETCH -------------------
function fetchPage($url, $pageNum, $userAgent)
{
$ch = curl_init();
// Only pass the page parameter – leave everything else to defaults.
$params = ['page' => $pageNum];
$fullUrl = $url . '?' . http_build_query($params);
curl_setopt_array($ch, [
CURLOPT_URL => $fullUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => $userAgent,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
]);
$html = curl_exec($ch);
if ($html === false) {
$err = curl_error($ch);
curl_close($ch);
throw new RuntimeException("cURL error fetching $fullUrl: $err");
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException("HTTP $status fetching $fullUrl");
}
return $html;
}
// -------------- PARSER -------------------
/**
* Parse a single HTML page into an array of records.
*
* Each record is an associative array with consistent keys.
*/
function parseWarrantPage($html)
{
// Strip HTML tags, keep whitespace/newlines
$text = html_entity_decode(strip_tags($html));
$lines = preg_split('/\R+/', $text); // split on any line break
$cleanLines = [];
foreach ($lines as $line) {
$line = trim($line);
if ($line !== '') {
$cleanLines[] = $line;
}
}
$records = [];
$i = 0;
$count = count($cleanLines);
while ($i < $count) {
$line = $cleanLines[$i];
// Header line pattern:
// "MM/DD/YYYY LASTNAME, FIRST CRIME County"
if (preg_match('/^(\d{2}\/\d{2}\/\d{4})\s+(.+?)\s{2,}(.+?)\s{2,}(.+)$/', $line, $m)) {
$record = [
'warrant_date_header' => $m[1],
'name_header' => trim($m[2]),
'crime_header' => trim($m[3]),
'county_header' => trim($m[4]),
'name' => '',
'doc_number' => '',
'supervision_county' => '',
'crime_type' => '',
'warrant_issue_date' => '',
'age' => '',
'birthdate' => '',
'height' => '',
'weight' => '',
'eye_color' => '',
'hair_color' => '',
'race' => '',
'hispanic' => '',
];
$i++;
// Read forward until next header or end
while ($i < $count) {
$line2 = $cleanLines[$i];
// If we hit another header line, stop this record
if (preg_match('/^(\d{2}\/\d{2}\/\d{4})\s+(.+?)\s{2,}(.+?)\s{2,}(.+)$/', $line2)) {
break;
}
// Map label/value pairs
if (stripos($line2, 'Name:') === 0) {
$record['name'] = trim(substr($line2, strlen('Name:')));
} elseif (stripos($line2, 'DOC Number:') === 0) {
$record['doc_number'] = trim(substr($line2, strlen('DOC Number:')));
} elseif (stripos($line2, 'Supervision County:') === 0) {
$record['supervision_county'] = trim(substr($line2, strlen('Supervision County:')));
} elseif (stripos($line2, 'Crime Type:') === 0) {
$record['crime_type'] = trim(substr($line2, strlen('Crime Type:')));
} elseif (stripos($line2, 'Date Issued:') === 0) {
$record['warrant_issue_date'] = trim(substr($line2, strlen('Date Issued:')));
} elseif (stripos($line2, 'Age:') === 0) {
$record['age'] = trim(substr($line2, strlen('Age:')));
} elseif (stripos($line2, 'Birthdate:') === 0) {
$record['birthdate'] = trim(substr($line2, strlen('Birthdate:')));
} elseif (stripos($line2, 'Height:') === 0) {
$record['height'] = trim(substr($line2, strlen('Height:')));
} elseif (stripos($line2, 'Weight:') === 0) {
$record['weight'] = trim(substr($line2, strlen('Weight:')));
} elseif (stripos($line2, 'Eye Color:') === 0) {
$record['eye_color'] = trim(substr($line2, strlen('Eye Color:')));
} elseif (stripos($line2, 'Hair Color:') === 0) {
$record['hair_color'] = trim(substr($line2, strlen('Hair Color:')));
} elseif (stripos($line2, 'Race:') === 0) {
$record['race'] = trim(substr($line2, strlen('Race:')));
} elseif (stripos($line2, 'Hispanic:') === 0) {
$record['hispanic'] = trim(substr($line2, strlen('Hispanic:')));
}
$i++;
}
$records[] = $record;
continue;
}
$i++;
}
return $records;
}
// -------------- MAIN SCRAPE LOOP -------------------
$page = 0;
$allRecords = [];
// Optional safety: stop after a high page number in case something goes weird
$maxPages = 500;
echo "Starting scrape...\n";
while ($page < $maxPages) {
echo "Fetching page $page...\n";
try {
$html = fetchPage($baseUrl, $page, $userAgent);
} catch (Exception $e) {
echo "Error fetching page $page: " . $e->getMessage() . "\n";
break;
}
$pageRecords = parseWarrantPage($html);
$countPage = count($pageRecords);
echo " Parsed $countPage records on this page.\n";
if ($countPage === 0) {
echo "No more records found. Stopping.\n";
break;
}
$allRecords = array_merge($allRecords, $pageRecords);
$page++;
// Be polite to their server.
sleep(1);
}
// -------------- WRITE CSV -------------------
if (empty($allRecords)) {
echo "No records collected. Nothing to write.\n";
exit(0);
}
// Determine columns dynamically from keys
$headers = array_keys($allRecords[0]);
$fp = fopen($outputCsv, 'w');
if (!$fp) {
throw new RuntimeException("Unable to open $outputCsv for writing.");
}
// Write header row
fputcsv($fp, $headers);
// Write data
foreach ($allRecords as $row) {
$line = [];
foreach ($headers as $h) {
$line[] = isset($row[$h]) ? $row[$h] : '';
}
fputcsv($fp, $line);
}
fclose($fp);
echo "Done. Wrote " . count($allRecords) . " records to $outputCsv\n";