Advertisement
Artur_Hopf

Untitled

Oct 23rd, 2019
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 13.90 KB | None | 0 0
  1. <?php
  2.  
  3. namespace common\models;
  4.  
  5. use Yii;
  6. use yii\base\Model;
  7. use keltstr\simplehtmldom\SimpleHTMLDom;
  8. use yii\helpers\Json;
  9.  
  10. class Parser extends Model
  11. {
  12.     public $url;
  13.     public $html;
  14.     public $old_watermark;
  15.  
  16.     const MAX_TRIES = 4;
  17.     const MAX_IMAGES = 7;
  18.     const PROXY_USER = "proxyuser:qwer4123";
  19.     const PROXY_FILE = "/home/pdftour/public_html/proxy.txt";
  20.  
  21.     public static function getProxy($all = false)
  22.     {
  23.         if ($file = file_get_contents(static::PROXY_FILE)) {
  24.             $proxies = explode("\n", $file);
  25.  
  26.             if ($all) {
  27.                 return $proxies;
  28.             }
  29.  
  30.             return trim($proxies[rand(0, count($proxies) - 1)]);
  31.         }
  32.  
  33.         return false;
  34.     }
  35.  
  36.     public static function testProxy($proxies, $url = "https://www.cian.ru/")
  37.     {
  38.         set_time_limit(0);
  39.  
  40.         $goodProxies = [];
  41.  
  42.         for ($i = 0; $i < count($proxies); $i++) {
  43.             $ch = curl_init($url);
  44.             curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  45.             curl_setopt($ch, CURLOPT_HTTPHEADER, [
  46.                 'Pragma: no-cache',
  47.                 'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2',
  48.                 'Upgrade-Insecure-Requests: 1',
  49.                 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
  50.                 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  51.                 'Cache-Control: no-cache',
  52.                 'Connection: keep-alive',
  53.             ]);
  54.  
  55.             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  56.             curl_setopt($ch, CURLOPT_TIMEOUT, 10);
  57.             curl_setopt($ch, CURLOPT_PROXY, $proxies[$i]);
  58.  
  59.             curl_setopt($ch, CURLOPT_PROXYUSERPWD, static::PROXY_USER);
  60.  
  61.             $data = curl_exec($ch);
  62.  
  63.             if (strlen($data) > 100000) {
  64.                 $goodProxies[] = $proxies[$i];
  65.             }
  66.         }
  67.         return $goodProxies;
  68.     }
  69.  
  70.  
  71.     public static function request($url)
  72.     {
  73.         $data = "";
  74.         for ($i = 0; $i < static::MAX_TRIES  * 2; $i++) {
  75.             $ch = curl_init($url);
  76.  
  77.             curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  78.             curl_setopt($ch, CURLOPT_HTTPHEADER, [
  79.                 'Pragma: no-cache',
  80.                 'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2',
  81.                 'Upgrade-Insecure-Requests: 1',
  82.                 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
  83.                 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  84.                 'Cache-Control: no-cache',
  85.                 'Connection: keep-alive',
  86.             ]);
  87.  
  88.             $proxy = static::getProxy();
  89.  
  90.             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  91.             curl_setopt($ch, CURLOPT_TIMEOUT, 9);
  92.             curl_setopt($ch, CURLOPT_PROXY, $proxy);
  93.             curl_setopt($ch, CURLOPT_PROXYUSERPWD, static::PROXY_USER);
  94.  
  95.             $data = curl_exec($ch);
  96. //            file_put_contents("/tmp/cian" . $proxy, $data);
  97.             if (strlen($data) > 1000) {
  98.                 return $data;
  99.             }
  100.         }
  101. //        file_put_contents("/tmp/cian", $data);
  102.         return false;
  103.     }
  104.  
  105.     public static function multiRequest($urls)
  106.     {
  107.         $responses = [];
  108.  
  109.         for ($i = 0; $i < static::MAX_TRIES && !empty($urls); $i++) {
  110.             $multi = curl_multi_init();
  111.             $channels = [];
  112.  
  113.             foreach ($urls as $index => $url) {
  114.                 $ch = curl_init($url);
  115.                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  116.                 curl_setopt($ch, CURLOPT_HTTPHEADER, [
  117.                     'Pragma: no-cache',
  118.                     'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2',
  119.                     'Upgrade-Insecure-Requests: 1',
  120.                     'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
  121.                     'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  122.                     'Cache-Control: no-cache',
  123.                     'Connection: keep-alive',
  124.                 ]);
  125.  
  126.                 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  127.                 curl_setopt($ch, CURLOPT_TIMEOUT, 20);
  128.                 curl_setopt($ch, CURLOPT_PROXY, static::getProxy());
  129.                 curl_setopt($ch, CURLOPT_PROXYUSERPWD, static::PROXY_USER);
  130.                 curl_multi_add_handle($multi, $ch);
  131.                 $channels[$index] = $ch;
  132.             }
  133.  
  134.             $running = NULL;
  135.             do {
  136.                 curl_multi_exec($multi, $running);
  137.             } while ($running > 0);
  138.  
  139.             foreach ($channels as $index => $channel) {
  140.                 $response = curl_multi_getcontent($channel);
  141.                 if (strlen($response) > 1000) {
  142.                     $responses[] = $response;
  143.                     unset($urls[$index]);
  144.                 }
  145.                 curl_multi_remove_handle($multi, $channel);
  146.             }
  147.  
  148.             curl_multi_close($multi);
  149.         }
  150.  
  151.         return $responses;
  152.     }
  153.  
  154.     public function loadHtml()
  155.     {
  156.         if ($response = static::request($this->url)) {
  157.  
  158.             $this->html = SimpleHTMLDom::str_get_html($response);
  159.             return true;
  160.         }
  161.         return false;
  162.     }
  163.  
  164.     public function parseHtml()
  165.     {
  166.  
  167.         $html = $this->html;
  168.  
  169. //        if (Yii::$app->user->id == 5) {
  170. //           echo $html;
  171. //            exit();
  172. //        }
  173.  
  174.  
  175. //        if ($_SERVER['REMOTE_ADDR'] == '176.100.15.166') {
  176. //            echo ($html);
  177. //            exit();
  178. //            return false;
  179. //        }
  180. //
  181.  
  182.  
  183.         if (empty($html)) {
  184.             return false;
  185.         }
  186.  
  187.         $model = new Realty();
  188.  
  189.  
  190.         $price = '';
  191.         if ($htmlBlock = $html->find('[itemprop="price"]', 0)) {
  192.          //   $price = static::whitespace(preg_replace('/[^\d]+/', '', $htmlBlock->plaintext));
  193.             $price = static::whitespace(str_replace('₽', 'руб', $htmlBlock->plaintext));
  194.         }
  195.  
  196.  
  197.         if (strpos($this->url , '/rent/') === false) {
  198.             $title = "Продажа ";
  199.         } else {
  200.             $title = "Аренда ";
  201.         }
  202.  
  203.         $address = '';
  204.         if ($htmlBlock = $html->find("address", 0)) {
  205.             $address = static::whitespace(str_replace('На карте', '', $htmlBlock->plaintext));
  206.         }
  207.  
  208.         if ($htmlBlock = $html->find('[class*="header-information--"] [class*="title--"]', 0)) {
  209.             $title .= static::whitespace($htmlBlock->plaintext) . ', ';
  210.         }
  211.  
  212.         $title .= $address;
  213.         $title = str_replace(" на длительный срок (от года)", "", $title);
  214.  
  215.  
  216.         $images = [];
  217.  
  218.         $imageUrls = [];
  219.  
  220.  
  221.         preg_match_all('/"thumbnailUrl":"([^"]+)"/', $html, $matches);
  222.         if (!empty($matches[1])) {
  223.             foreach ($matches[1] as $url) {
  224.                 $imageUrls[] = str_replace(['\u002F', '1.jpg'], ['/', '2.jpg'], $url);
  225.             }
  226.         }
  227.  
  228. //        foreach ($html->find('img[class^="photo"]') as $image) {
  229. //            $imageUrls[] = str_replace(['\u002F', '1.jpg'], ['/', '2.jpg'], $image->getAttribute("src"));
  230. //        }
  231.  
  232.  
  233.         $imageResponses = static::multiRequest($imageUrls);
  234.  
  235.         foreach ($imageResponses as $response) {
  236.             $filename = Yii::$app->security->generateRandomString() . ".jpg";
  237.             $fullName = Yii::getAlias('@frontend/web/images/tmp/') . $filename;
  238.  
  239.             file_put_contents($fullName, $response);
  240.  
  241.             try {
  242.                 if (exif_imagetype($fullName) == IMAGETYPE_JPEG) {
  243.                     $src = imagecreatefromjpeg($fullName);
  244.                     $imageWidth = imagesx($src);
  245.                     $imageHeight = imagesy($src);
  246.  
  247.                     if ($imageHeight < 100) {
  248.                      //   throw new \Exception("small image");
  249.                     }
  250.                  /*  
  251.                     if (!empty($this->old_watermark)) {
  252.                         $imageHeight = $imageHeight - 81;
  253.                     } else {
  254.                         $imageHeight = $imageHeight - 138;  
  255.                     }                    
  256.  
  257.                     $ratio = 2/3;
  258.  
  259.                     $sourceY = $sourceX = 0;
  260.                     $newImageHeight = $imageHeight;
  261.                     $newImageWidth = $imageWidth;
  262.                     if ($imageHeight / $imageWidth > $ratio) {
  263.                         $newImageHeight = intval($imageWidth * $ratio);
  264.                         $sourceY = intval(($imageHeight - $newImageHeight) / 2);
  265.                     } else {
  266.                         $newImageWidth = intval($newImageHeight / $ratio);
  267.                         $sourceX = intval(($imageWidth - $newImageWidth) / 2);
  268.                     }
  269.  
  270.                    
  271.                     $dest = imagecreatetruecolor($newImageWidth, $newImageHeight);
  272.                     imagecopy($dest, $src, 0, 0, $sourceX, $sourceY, $newImageWidth, $newImageHeight);
  273.                     */
  274.     //                if (empty($this->old_watermark)) {
  275.       //                  $white = imagecolorallocate($dest, 255, 255, 255);
  276.         //                imagefilledrectangle ($dest, $newImageWidth - 340, $newImageHeight - 170, $newImageWidth - 1, $newImageHeight - 1, 0xffffff);
  277.           //          }
  278.                    
  279.                    
  280.                  //   imagejpeg($dest, $fullName);
  281.                     //imagejpeg($src, $fullName);
  282.  
  283.                     $images[] = $filename;
  284.                 } else {
  285.                     unlink($fullName);
  286.                 }
  287.             } catch (\Exception $e) {
  288.                 try {
  289.                     unlink($fullName);
  290.                 } catch (\Exception $e) {
  291.  
  292.                 }
  293.             }
  294.         }
  295.  
  296.         $description = '';
  297.         if ($htmlBlock = $html->find('p[class*="description-text--"]', 0)) {
  298.     /*        $description = $htmlBlock->innertext;
  299.             $description = static::whitespace($description);
  300.             $description = preg_replace('/^.+<br\/?>.*<br\/?>/', '', $description);
  301.             $description = preg_replace('/<div.+$/', '', $description);
  302.             $description = preg_replace('/<br \/>.+$/', '', $description);*/
  303.             $description = $htmlBlock->plaintext;
  304.         }
  305.  
  306.  
  307.         $fields = [];
  308.  
  309.         $fields['Адрес'] = $address;
  310.  
  311.  
  312.  
  313.         if ($htmlBlock = $html->find('[class*="underground_link--"]', 0)) {
  314.             $fields['Метро'] = static::whitespace($htmlBlock->plaintext);
  315.         }
  316.  
  317.         if ($htmlBlock = $html->find('[class*="underground_time--"]', 0)) {
  318.             $fields['До метро'] = static::whitespace(str_replace(',', '', $htmlBlock->plaintext));
  319.         }
  320.  
  321. //        foreach ($html->find("table.object_descr_props tr") as $tableRow) {
  322. //            if (($tableTh = $tableRow->find("th", 0)) && ($tableTd = $tableRow->find("td", 0))
  323. //                && !empty($name = static::whitespace($tableTh->plaintext))
  324. //                && !empty($value = static::whitespace($tableTd->plaintext))) {
  325. //                $fields[str_replace(":", "", $name)] = $value;
  326. //            }
  327. //        }
  328. //
  329. //
  330. //        if ($htmlBlock = $html->find(".cf-comm-offer-detail__section", 0)) {
  331. //            $nameRows = $html->find(".cf-comm-offer-detail__prop-name");
  332. //            $valRows = $html->find(".cf-comm-offer-detail__prop-val");
  333. //            if ($nameRows && $valRows) {
  334. //                for ($i = 0; $i < count($nameRows) && $i < count($valRows); $i++) {
  335. //                    if (!empty($name = static::whitespace($nameRows[$i]->plaintext))
  336. //                        && !empty($value = static::whitespace($valRows[$i]->plaintext))
  337. //                    ) {
  338. //                        $fields[str_replace(":", "", $name)] = $value;
  339. //                    }
  340. //                }
  341. //            }
  342. //        }
  343.  
  344.  
  345.  
  346.         foreach ($html->find('[class*="info-block--"] [class*="info--"]') as $infoBlock) {
  347.             if (($nameBlock = $infoBlock->find('[class*="info-title--"]', 0)) && ($valueBlock = $infoBlock->find('[class*="info-text"]', 0))
  348.                 && !empty($name = static::whitespace($nameBlock->plaintext))
  349.                 && !empty($value = static::whitespace($valueBlock->plaintext))) {
  350.                 $fields[str_replace(":", "", $name)] = $value;
  351.             }
  352.         }
  353.  
  354.  
  355.         $coordinates = '';
  356.         try {
  357.             preg_match('/{"lng":(\d+.\d+),"lat":(\d+.\d+)}/', $html->outertext, $matches);
  358.             $coordinates = $matches[1] . "," . $matches[2];
  359.         } catch (\Exception $e) {
  360.             $coordinates = '';
  361.         }
  362.  
  363.  
  364.         $model->attributes = [
  365.             'url' => $this->url,
  366.             'image_urls' => Json::encode($images),
  367.             'title' => $title,
  368.             'coordinates' => $coordinates,
  369.             'price' => $price,
  370.             'user_id' => Yii::$app->user->id,
  371.             'description' => $description,
  372.             'fields' => Json::encode($fields),
  373.         ];
  374.  
  375. //        file_put_contents(__DIR__ .  "/../../frontend/runtime/loglog", print_r($model->attributes, true));
  376.  
  377.         if ($model->save()) {
  378.             $activity = new UserActivity();
  379.             $activity->attributes = [
  380.                 'user_id' => Yii::$app->user->id,
  381.                 'type' => UserActivity::TYPE_PARSING,
  382.                 'url' => $this->url,
  383.             ];
  384.             $activity->save();
  385.             return true;
  386.         }
  387.         file_put_contents(__DIR__ .  "/../../frontend/runtime/loglog", print_r($model->errors, true));
  388.  
  389.         return false;
  390.     }
  391.  
  392.     public static function whitespace($string)
  393.     {
  394.         return html_entity_decode(trim(preg_replace('/\s+/', ' ', str_replace("&nbsp;", " ", $string))));
  395.     }
  396. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement