commit
						4760eaf987
					
				@ -0,0 +1,5 @@ | 
				
			|||||||
 | 
					.idea/ | 
				
			||||||
 | 
					out/ | 
				
			||||||
 | 
					cookie.txt | 
				
			||||||
 | 
					cookie-wget.txt | 
				
			||||||
 | 
					vesmir.cz | 
				
			||||||
@ -0,0 +1,97 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const UA = 'Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_doc($url) { | 
				
			||||||
 | 
						return new Html(get($url)->content); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_file($url) { | 
				
			||||||
 | 
						return get($url)->content; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_or_post($url, $mergeoptions) { | 
				
			||||||
 | 
						$options = array( | 
				
			||||||
 | 
							CURLOPT_USERAGENT => UA, //set user agent | 
				
			||||||
 | 
							CURLOPT_COOKIEFILE => "cookie.txt", //set cookie file | 
				
			||||||
 | 
							CURLOPT_COOKIEJAR => "cookie.txt", //set cookie jar | 
				
			||||||
 | 
							CURLOPT_COOKIESESSION => false, | 
				
			||||||
 | 
							CURLOPT_RETURNTRANSFER => true,     // return web page | 
				
			||||||
 | 
							CURLOPT_HEADER => false,    // don't return headers | 
				
			||||||
 | 
							CURLOPT_FOLLOWLOCATION => true,     // follow redirects | 
				
			||||||
 | 
							CURLOPT_ENCODING => "",       // handle all encodings | 
				
			||||||
 | 
							CURLOPT_AUTOREFERER => true,     // set referer on redirect | 
				
			||||||
 | 
							CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect | 
				
			||||||
 | 
							CURLOPT_TIMEOUT => 120,      // timeout on response | 
				
			||||||
 | 
							CURLOPT_MAXREDIRS => 10,       // stop after 10 redirects | 
				
			||||||
 | 
						); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						foreach ($mergeoptions as $k => $v) { | 
				
			||||||
 | 
							$options[$k] = $v; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$ch = curl_init($url); | 
				
			||||||
 | 
						curl_setopt_array($ch, $options); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// this function is called by curl for each header received | 
				
			||||||
 | 
						$response_headers = []; | 
				
			||||||
 | 
						curl_setopt($ch, CURLOPT_HEADERFUNCTION, | 
				
			||||||
 | 
							function($curl, $header) use (&$response_headers) | 
				
			||||||
 | 
							{ | 
				
			||||||
 | 
								$len = strlen($header); | 
				
			||||||
 | 
								$header = explode(':', $header, 2); | 
				
			||||||
 | 
								if (count($header) < 2) // ignore invalid headers | 
				
			||||||
 | 
									return $len; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$name = strtolower(trim($header[0])); | 
				
			||||||
 | 
								if (!array_key_exists($name, $response_headers)) | 
				
			||||||
 | 
									$response_headers[$name] = [trim($header[1])]; | 
				
			||||||
 | 
								else | 
				
			||||||
 | 
									$response_headers[$name][] = trim($header[1]); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return $len; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$content = curl_exec($ch); | 
				
			||||||
 | 
						$err = curl_errno($ch); | 
				
			||||||
 | 
						$errmsg = curl_error($ch); | 
				
			||||||
 | 
						$header = curl_getinfo($ch); | 
				
			||||||
 | 
						curl_close($ch); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$header['errno'] = $err; | 
				
			||||||
 | 
						$header['errmsg'] = $errmsg; | 
				
			||||||
 | 
						$header['headers'] = $response_headers; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	echo "Result:\n"; | 
				
			||||||
 | 
					//	print_r($header); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$header['content'] = $content; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ($header['http_code'] != 200) { | 
				
			||||||
 | 
							print_r($header); | 
				
			||||||
 | 
							throw new \Exception("Error status: $header[http_code]"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (object) $header; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get($url) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						echo "Sending GET to: $url\n"; | 
				
			||||||
 | 
						return get_or_post($url, [ | 
				
			||||||
 | 
							CURLOPT_CUSTOMREQUEST => "GET",        //set request type post or get | 
				
			||||||
 | 
							CURLOPT_POST => false,        //set to GET | 
				
			||||||
 | 
						]); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function post($url, $fields) | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						echo "Sending POST to: $url\n"; | 
				
			||||||
 | 
						print_r($fields); | 
				
			||||||
 | 
						return get_or_post($url, [ | 
				
			||||||
 | 
							CURLOPT_CUSTOMREQUEST => "POST",        //set request type post or get | 
				
			||||||
 | 
							CURLOPT_POST => true,        //set to GET | 
				
			||||||
 | 
							CURLOPT_POSTFIELDS => $fields, | 
				
			||||||
 | 
						]); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,186 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PARSER_DEBUG = 0; | 
				
			||||||
 | 
					const XPATH_DEBUG = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** | 
				
			||||||
 | 
					 * Trait DomQuery | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
					 * requires: | 
				
			||||||
 | 
					 * | 
				
			||||||
 | 
						$this->dom = $dom; | 
				
			||||||
 | 
						$this->contextnode = null; | 
				
			||||||
 | 
					 */ | 
				
			||||||
 | 
					trait DomQuery { | 
				
			||||||
 | 
						public function find(string $pat) : Node | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$els = $this->findAll($pat); | 
				
			||||||
 | 
							if (!count($els)) { | 
				
			||||||
 | 
								if (PARSER_DEBUG) { | 
				
			||||||
 | 
									echo "---- match failed; context: ---\n"; | 
				
			||||||
 | 
									echo $this->toXml() ."\n"; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								throw new \Exception("No match: $pat"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							if (count($els) > 1) { | 
				
			||||||
 | 
								if (PARSER_DEBUG) { | 
				
			||||||
 | 
									echo "Query results:\n"; | 
				
			||||||
 | 
									foreach ($els as $el) { | 
				
			||||||
 | 
										echo $el->toXml()."\n"; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
								throw new \Exception("Multiple match (".count($els)."x): $pat"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return $els[0]; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * @param $pat | 
				
			||||||
 | 
						 * @return array|Node[] | 
				
			||||||
 | 
						 * @throws Exception | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function findAll(string $pat) : array | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							# node | 
				
			||||||
 | 
							if (preg_match('/^([a-z0-9_-]+)$/i', $pat, $matches)) { | 
				
			||||||
 | 
								return $this->x("//$matches[1]"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# .class, node.class | 
				
			||||||
 | 
							if (preg_match('/^(?P<elem>[a-z0-9_-]*)\.(?P<cls>[a-z0-9_-]+)$/i', $pat, $matches)) { | 
				
			||||||
 | 
								$elem = $matches['elem'] ?: '*'; | 
				
			||||||
 | 
								return $this->x("//{$elem}[contains(concat(' ',normalize-space(@class),' '),' $matches[cls] ')]"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// #id | 
				
			||||||
 | 
							if (preg_match('/^#(\w+)$/', $pat, $matches)) { | 
				
			||||||
 | 
								return $this->x("//*[id='$matches[1]']"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# [attr=value], node[attr=value] (allows quotes) | 
				
			||||||
 | 
							if (preg_match('/^(?P<elem>[a-z0-9_-]*)\[(?P<attr>[a-z0-9_-]+)(?P<op>[$*~^]|)=[\'"]?(?P<val>[^\'"\]]+)[\'"]?\]$/', $pat, $matches)) { | 
				
			||||||
 | 
								$elem = $matches['elem'] ?: '*'; | 
				
			||||||
 | 
								$op = $matches['op']; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								switch ($op) { | 
				
			||||||
 | 
									case '': | 
				
			||||||
 | 
										return $this->x("//{$elem}[@$matches[attr]='$matches[val]']"); | 
				
			||||||
 | 
									case '^': | 
				
			||||||
 | 
										return $this->x("//{$elem}[starts-with(@$matches[attr], '$matches[val]')]"); | 
				
			||||||
 | 
									// this doesnt work.. | 
				
			||||||
 | 
					//				case '$': | 
				
			||||||
 | 
					//					$vlen = strlen($matches['val']); | 
				
			||||||
 | 
					//					return $this->x("//{$elem}['$matches[val]' = substring(@$matches[attr], string-length(@$matches[attr]) - $vlen)]"); | 
				
			||||||
 | 
									case '*': | 
				
			||||||
 | 
									case '~': | 
				
			||||||
 | 
										return $this->x("//{$elem}[contains(@$matches[attr], '$matches[val]')]"); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# [attr^=value], node[attr^=value] (allows quotes) | 
				
			||||||
 | 
							if (preg_match('/^(?P<elem>[a-z0-9_-]*)\[(?P<attr>[a-z0-9_-]+)^=[\'"]?(?P<val>[^\'"\]]+)[\'"]?\]$/', $pat, $matches)) { | 
				
			||||||
 | 
								$elem = $matches['elem'] ?: '*'; | 
				
			||||||
 | 
								return $this->x("//{$elem}[@$matches[attr]='$matches[val]']"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# [attr], node[attr] | 
				
			||||||
 | 
							if (preg_match('/^(?P<elem>[a-z0-9_-]*)\[(?P<attr>[a-z0-9_-]+)\]$/', $pat, $matches)) { | 
				
			||||||
 | 
								$elem = $matches['elem'] ?: '*'; | 
				
			||||||
 | 
								return $this->x("//{$elem}[@$matches[attr]]"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							throw new \Exception("Unknown pattern: $pat"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function x(string $x) : array | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$xpath = new DOMXpath($this->dom); | 
				
			||||||
 | 
							if (strpos($x, '//') === 0 && $this->contextnode) { | 
				
			||||||
 | 
								$x = '.' . $x; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (XPATH_DEBUG) echo "\nxpath is: $x\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$elements = $xpath->query($x, $this->contextnode) ?? []; | 
				
			||||||
 | 
							$elems = []; | 
				
			||||||
 | 
							foreach($elements as $e) { | 
				
			||||||
 | 
								$elems[] = new Node($this->dom, $e); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return $elems; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Html | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						use DomQuery; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function __construct(string $html) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$dom = new DomDocument(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (PARSER_DEBUG) echo "Creating HTML parser from:\n" . $html . "\n\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@$dom->loadHTML($html); // suppress spammy warnings | 
				
			||||||
 | 
							$this->dom = $dom; | 
				
			||||||
 | 
							$this->contextnode = null; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function toXml() : string | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->dom->saveXml(); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Node | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						use DomQuery; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function __construct(DOMDocument $dom, DOMNode $element) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$this->dom = $dom; | 
				
			||||||
 | 
							$this->element = $element; | 
				
			||||||
 | 
							$this->contextnode = $element; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function __get($name) | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->element->getAttribute($name); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function text() : string | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->element->nodeValue ?? ''; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * @return array|Node[] | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function childNodes() : array | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$elems = []; | 
				
			||||||
 | 
							foreach($this->element->childNodes as $e) { | 
				
			||||||
 | 
								$elems[] = new Node($this->dom, $e); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return $elems; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** | 
				
			||||||
 | 
						 * @return Node | 
				
			||||||
 | 
						 */ | 
				
			||||||
 | 
						public function childNode() : Node | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							$cn = $this->childNodes(); | 
				
			||||||
 | 
							if (count($cn) > 1) { | 
				
			||||||
 | 
								throw new \Exception("More than one childnode."); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							return $cn[0]; | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function toXml() : string | 
				
			||||||
 | 
						{ | 
				
			||||||
 | 
							return $this->element->ownerDocument->saveXml($this->element); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,279 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MAX_DIR_NAME_LEN = 40; | 
				
			||||||
 | 
					const SKIP_EXISTING = true; | 
				
			||||||
 | 
					const VESMIR_CZ = 'https://vesmir.cz'; | 
				
			||||||
 | 
					const VESMIR_LOGIN = ""; | 
				
			||||||
 | 
					const VESMIR_PASSWORD = ""; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require_once "http.inc"; | 
				
			||||||
 | 
					require_once "parse.inc"; | 
				
			||||||
 | 
					require_once "session.inc"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function scrape_issue($rocnik_dir, $rocnik, $cislo, Html $doc) { | 
				
			||||||
 | 
						$cislo_dir = $rocnik_dir . '/' . $cislo; | 
				
			||||||
 | 
						if (!file_exists($cislo_dir)) { | 
				
			||||||
 | 
							mkdir($cislo_dir); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo "\nStahuji cislo $rocnik/$cislo\n\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$n_clanky = $doc->find('.clanky'); | 
				
			||||||
 | 
						$clankyItems = $n_clanky->findAll('.row'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$cl_num = 0; | 
				
			||||||
 | 
						$aktualni_h4 = null; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						foreach ($clankyItems as $row) { | 
				
			||||||
 | 
							try { | 
				
			||||||
 | 
								$hh = $row->find('h4'); | 
				
			||||||
 | 
								$aktualni_h4 = $hh->text(); | 
				
			||||||
 | 
								echo "\n~ Skupina clanku: $aktualni_h4 ~\n"; | 
				
			||||||
 | 
								continue; | 
				
			||||||
 | 
							} catch(Exception $e) { | 
				
			||||||
 | 
								/* ok.. */ | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ($row->class != 'clankyItem row') { | 
				
			||||||
 | 
								echo "Skip non-article\n"; | 
				
			||||||
 | 
								continue; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try { | 
				
			||||||
 | 
								//echo $row->toXml(); | 
				
			||||||
 | 
								$num = ++$cl_num; // zvysit pocitadlo... | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$h3 = $row->find('h3'); | 
				
			||||||
 | 
								$a = $h3->find('a'); | 
				
			||||||
 | 
								$clanek_url = VESMIR_CZ . $a->href; | 
				
			||||||
 | 
								$clanek_nazev = $a->text(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Get slug | 
				
			||||||
 | 
								preg_match('|/([^./]+)\.html$|', $clanek_url, $m); | 
				
			||||||
 | 
								$slug = $m[1]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Get dirname | 
				
			||||||
 | 
								$fname = $num . ' - ' . $clanek_nazev; | 
				
			||||||
 | 
								$fname = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\). ])", '', $fname); | 
				
			||||||
 | 
								$fname = mb_ereg_replace("([\.]{2,})", '', $fname); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (strlen($fname) > MAX_DIR_NAME_LEN) { | 
				
			||||||
 | 
									$fname = substr($fname, 0, strrpos($fname, ' ', -(strlen($fname) - MAX_DIR_NAME_LEN))); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Ensure dir exists | 
				
			||||||
 | 
								$clanek_dir = $cislo_dir . '/' . $fname; | 
				
			||||||
 | 
								if (!file_exists($clanek_dir)) { | 
				
			||||||
 | 
									mkdir($clanek_dir); | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								echo "\n- $rocnik/$cislo -> Clanek #$num: $clanek_nazev -\nUrl: $clanek_url\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$perex = null; | 
				
			||||||
 | 
								try { | 
				
			||||||
 | 
									$perex = $row->find('.perex')->text(); | 
				
			||||||
 | 
								} catch (Exception $e) { | 
				
			||||||
 | 
									echo "No perex. ".$e->getMessage()."\n"; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$thumbfile = null; | 
				
			||||||
 | 
								try { | 
				
			||||||
 | 
									if (file_exists($clanek_dir . '/thumb.jpg')) { | 
				
			||||||
 | 
										$thumbfile = 'thumb.jpg'; | 
				
			||||||
 | 
									} else { | 
				
			||||||
 | 
										$thumb = $row->find('img.img-responsive'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										$f = get_file(VESMIR_CZ . $thumb->src); | 
				
			||||||
 | 
										file_put_contents($clanek_dir . '/thumb.jpg', $f); | 
				
			||||||
 | 
										$thumbfile = 'thumb.jpg'; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} catch (Exception $e) { | 
				
			||||||
 | 
									echo "No thumb. ".$e->getMessage()."\n"; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$author_names = []; | 
				
			||||||
 | 
								try { | 
				
			||||||
 | 
									$authors = $row->find('.authors'); | 
				
			||||||
 | 
									$author_links = $authors->findAll('a'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									foreach ($author_links as $al) { | 
				
			||||||
 | 
										$author_names[] = $al->text(); | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								} catch (Exception $e) { | 
				
			||||||
 | 
									echo "!! No .authors div\n"; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$merged_authors = implode(', ', $author_names); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(SKIP_EXISTING && file_exists($clanek_dir . '/clanek.json')) { | 
				
			||||||
 | 
									echo "ARTICLE ALREADY DL'D, SKIP\n"; | 
				
			||||||
 | 
									continue; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$resp = get_file($clanek_url); | 
				
			||||||
 | 
								file_put_contents($clanek_dir . '/orig.html', $resp); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$article_doc = new Html($resp); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$attachments = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Try to download attachments (pdf version...) | 
				
			||||||
 | 
								try { | 
				
			||||||
 | 
									$dmedia = $article_doc->find('.media'); | 
				
			||||||
 | 
									foreach ($dmedia->findAll('a[href]') as $item) { | 
				
			||||||
 | 
										$href = VESMIR_CZ . $item->href; | 
				
			||||||
 | 
										echo "> Downloading: " . $item->text() . "\n" . $href; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										$fname = uniqid() . '.pdf'; // it's probably a pdf | 
				
			||||||
 | 
										if ($item->text() == 'článek ve formátu pdf') { | 
				
			||||||
 | 
											$isarticlepdf = true; | 
				
			||||||
 | 
											$fname = $slug . '.pdf'; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										$resp = get($href); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (isset($resp->headers['content-disposition'])) { | 
				
			||||||
 | 
											$first = $resp->headers['content-disposition'][0]; | 
				
			||||||
 | 
											list(, $orig_fname) = explode('filename=', $first); | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
										if (!$isarticlepdf) { | 
				
			||||||
 | 
											$fname = $orig_fname; | 
				
			||||||
 | 
										} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										file_put_contents($clanek_dir . '/' . $fname, $resp->content); | 
				
			||||||
 | 
										unset($resp->content); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										$attachments[] = [ | 
				
			||||||
 | 
											'url' => $href, | 
				
			||||||
 | 
											'popis' => $item->text(), | 
				
			||||||
 | 
											'nazev' => $orig_fname, | 
				
			||||||
 | 
											'soubor' => $fname, | 
				
			||||||
 | 
										]; | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} catch(Exception $e) { | 
				
			||||||
 | 
									echo "Error finding media links: ".$e->getMessage()."\n"; | 
				
			||||||
 | 
								} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$adiv = $article_doc->find('div.article'); | 
				
			||||||
 | 
								$body = $adiv->toXml(); // serialize the body div | 
				
			||||||
 | 
								$body = str_replace('
', '', $body); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$picnum = 0; | 
				
			||||||
 | 
								$body = preg_replace_callback('|src="(/images/[^"]+)"|', function($m) use ($clanek_dir, &$picnum) { | 
				
			||||||
 | 
									$uri = $m[1]; | 
				
			||||||
 | 
									$url = VESMIR_CZ . $uri; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									preg_match('|/([^/]+)$|', $uri, $m); | 
				
			||||||
 | 
									$img_slug = $m[1]; | 
				
			||||||
 | 
									$img_fname = 'img_' . ($picnum++) . '_' . $img_slug; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									try { | 
				
			||||||
 | 
										$f = get_file($url); | 
				
			||||||
 | 
										file_put_contents($clanek_dir . '/' . $img_fname, $f); | 
				
			||||||
 | 
										return "src=\"".htmlspecialchars($img_fname)."\""; | 
				
			||||||
 | 
									} catch(\Exception $e) { | 
				
			||||||
 | 
										echo "Error getting img $uri\n"; | 
				
			||||||
 | 
										echo $e->getMessage(); | 
				
			||||||
 | 
										echo $e->getTraceAsString(); | 
				
			||||||
 | 
										return $m[0]; // no subst. | 
				
			||||||
 | 
									} | 
				
			||||||
 | 
								}, $body); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$nazev_e = htmlspecialchars($clanek_nazev); | 
				
			||||||
 | 
								$merged_authors_e = htmlspecialchars($merged_authors); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$cleaned = <<<DOC | 
				
			||||||
 | 
					<!DOCTYPE html> | 
				
			||||||
 | 
					<html lang="cs"> | 
				
			||||||
 | 
					<head> | 
				
			||||||
 | 
					<meta charset="utf-8"> | 
				
			||||||
 | 
					<title>$nazev_e</title> | 
				
			||||||
 | 
					<link href="../../../style.css" rel="stylesheet" type="text/css" /> | 
				
			||||||
 | 
					</head> | 
				
			||||||
 | 
					<body> | 
				
			||||||
 | 
					<h1 class="article-name">$nazev_e</h1> | 
				
			||||||
 | 
					<p class="authors">$merged_authors_e</p> | 
				
			||||||
 | 
					<!-- article begin --> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$body | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- article end --> | 
				
			||||||
 | 
					</body> | 
				
			||||||
 | 
					</html> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DOC; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								file_put_contents($clanek_dir . '/clanek.html', $cleaned); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$metadata = [ | 
				
			||||||
 | 
									'nazev' => $clanek_nazev, | 
				
			||||||
 | 
									'slug' => $slug, | 
				
			||||||
 | 
									'url' => $clanek_url, | 
				
			||||||
 | 
									'autori' => $author_names, | 
				
			||||||
 | 
									'rocnik' => $rocnik, | 
				
			||||||
 | 
									'cislo' => $cislo, | 
				
			||||||
 | 
									'poradi' => $cl_num, | 
				
			||||||
 | 
									'prilohy' => $attachments, | 
				
			||||||
 | 
									'thumb' => $thumbfile, | 
				
			||||||
 | 
									'perex' => $perex, | 
				
			||||||
 | 
								]; | 
				
			||||||
 | 
								file_put_contents($clanek_dir . '/clanek.json', json_encode($metadata, 128|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} catch (Exception $e) { | 
				
			||||||
 | 
								echo $e->getMessage() . "\n" . $e->getTraceAsString() . "\n"; | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function scrape_year($year) { | 
				
			||||||
 | 
						$doc = get_doc(VESMIR_CZ . "/cz/casopis/archiv-casopisu/$year/"); | 
				
			||||||
 | 
						$obalky = $doc->findAll('.vesmirObalka'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$rocnik_dir = __DIR__ . '/out/' . $year; | 
				
			||||||
 | 
						if (!file_exists($rocnik_dir)) { | 
				
			||||||
 | 
							mkdir($rocnik_dir); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						foreach ($obalky as $obalka) { | 
				
			||||||
 | 
							$a = $obalka->childNode(); | 
				
			||||||
 | 
							$url_cislo = $a->href; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							echo $url_cislo.PHP_EOL; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!preg_match('|/(\d+)/cislo-(\d+)/$|', $url_cislo, $m)) { | 
				
			||||||
 | 
								die("weird format $url_cislo"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
							echo "== Rocnik $m[1], cislo $m[2] ==\n"; | 
				
			||||||
 | 
							$rocnik = $m[1]; | 
				
			||||||
 | 
							$cislo = $m[2]; | 
				
			||||||
 | 
							$ident = "$rocnik-$cislo"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$i = $a->childNode(); | 
				
			||||||
 | 
							$url_thumb = $i->src; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$url_thumb = str_replace("?h=180", "?h=1800", $url_thumb); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							echo "Casopis URL: $url_cislo\nObalka URL: $url_thumb\n\n"; | 
				
			||||||
 | 
							$obalka_file = $rocnik_dir . "/$ident.jpg"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!file_exists($obalka_file)) { | 
				
			||||||
 | 
								echo "Stahuji obalku...\n"; | 
				
			||||||
 | 
								$c = get_file(VESMIR_CZ . $url_thumb); | 
				
			||||||
 | 
								file_put_contents($obalka_file, $c); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							$c = get_doc(VESMIR_CZ . $url_cislo); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							scrape_issue($rocnik_dir, $rocnik, $cislo, $c); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ensure_logged_in(); | 
				
			||||||
 | 
					//scrape_year(2019); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for ($i = 2019; $i >= 1994; $i--) { | 
				
			||||||
 | 
						ensure_logged_in(); | 
				
			||||||
 | 
						scrape_year($i); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,87 @@ | 
				
			|||||||
 | 
					<?php | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function solveChallenge(Html $doc) : int { | 
				
			||||||
 | 
						$challenge = $doc->find('[for=spamProtectionDisableResult]')->text(); | 
				
			||||||
 | 
						echo "Challenge is: $challenge\n"; | 
				
			||||||
 | 
						if (preg_match('/(\d+) (plus|mínus) (\d+)/', $challenge, $m)) { | 
				
			||||||
 | 
							$a = +$m[1]; | 
				
			||||||
 | 
							$op = $m[2] == 'plus' ? 1 : -1; | 
				
			||||||
 | 
							$b = +$m[3]; | 
				
			||||||
 | 
							$r = $a + $op * $b; | 
				
			||||||
 | 
							echo "Result: $r\n"; | 
				
			||||||
 | 
							return $r; | 
				
			||||||
 | 
						} else { | 
				
			||||||
 | 
							throw new Exception("Unexpected challenge: $challenge"); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function login() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						echo "----- attempting to login -----\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return post( "https://vesmir.cz/usrlogon.do", [ | 
				
			||||||
 | 
							"username" => VESMIR_LOGIN, | 
				
			||||||
 | 
							"password" => VESMIR_PASSWORD, | 
				
			||||||
 | 
							"docId" => 9573, | 
				
			||||||
 | 
							"doShowdocAction" => "/usrlogon.do", | 
				
			||||||
 | 
							"emailLogon" => false, | 
				
			||||||
 | 
							"origDocId" => 9573, | 
				
			||||||
 | 
						]); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function disableAntispam() | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
						echo "----- disabling antispam -----\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$r = get("https://vesmir.cz/components/form/spamprotectiondisable.jsp?backurl=%2Fcz%2Fuzivatel.html"); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$doc = new Html($r->content); | 
				
			||||||
 | 
						$solved = solveChallenge($doc); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$result = post( "https://vesmir.cz/components/form/spamprotectiondisable.jsp", [ | 
				
			||||||
 | 
							"result" => $solved, | 
				
			||||||
 | 
							"__token" => $doc->find('[name=__token]')->value, | 
				
			||||||
 | 
							"backurl" => "/cz/uzivatel.html", | 
				
			||||||
 | 
							"hash" => $doc->find('[name=hash]')->value, | 
				
			||||||
 | 
						]); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (preg_match("/Zadaný výsledek je správný/", $result->content)) { | 
				
			||||||
 | 
							echo "Anti-spam succeeded.\n"; | 
				
			||||||
 | 
							return $result; | 
				
			||||||
 | 
						} else { | 
				
			||||||
 | 
							print_r($result); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							throw new Exception("Failed to disable antispam."); | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function dump_cookie_file_for_wget() { | 
				
			||||||
 | 
					//	echo "Exporting cookie for WGET\n"; | 
				
			||||||
 | 
					//	$c = file_get_contents("cookie.txt"); | 
				
			||||||
 | 
					//	$c = str_replace('#HttpOnly_', '', $c); | 
				
			||||||
 | 
					//	file_put_contents('cookie-wget.txt', $c); | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ensure_logged_in() { | 
				
			||||||
 | 
						// get a session cookie | 
				
			||||||
 | 
						$r = get("https://vesmir.cz/cz/uzivatel.html"); | 
				
			||||||
 | 
						if (strpos($r->content, '/logoff.do?forward=/cz/') !== false) { | 
				
			||||||
 | 
							echo "Already logged in!\n"; | 
				
			||||||
 | 
							dump_cookie_file_for_wget(); | 
				
			||||||
 | 
							return true; | 
				
			||||||
 | 
						} else { | 
				
			||||||
 | 
							echo "Need login!\n"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							disableAntispam(); | 
				
			||||||
 | 
							get("https://vesmir.cz/cz/uzivatel.html"); | 
				
			||||||
 | 
							$result = login(); | 
				
			||||||
 | 
							if (strpos($r->content, '/logoff.do?forward=/cz/') !== false) { | 
				
			||||||
 | 
								echo "Logged in!\n"; | 
				
			||||||
 | 
								dump_cookie_file_for_wget(); | 
				
			||||||
 | 
								return true; | 
				
			||||||
 | 
							} else { | 
				
			||||||
 | 
								print_r($result); | 
				
			||||||
 | 
								throw new Exception("--- LOGIN FAILED! ---"); | 
				
			||||||
 | 
							} | 
				
			||||||
 | 
						} | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue