1

Тема: Не виходить пропарсити мітки на Stackoverflow

Хочу зібрати певну статистику зі stackoverflow, але для незалогінених користувачів доступно вибрати лише одну із міток, а не декілька підряд, як мені треба. Коли намагаюсь curl'ом спарсити

http://stackoverflow.com/questions/tagged/javascript+jquery

то мене перекидає на

http://stackoverflow.com/questions/tagged/javascript

Ось як я намагаюсь відправляти запити

$url = 'http://stackoverflow.com/questions/tagged/javascript+jquery';
$cookie_file = 'cookie_file.txt';
$cookie_jar = 'cookie_jar.txt';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
curl_setopt($ch, CURLOPT_COOKIE, 'тут я вказую свої куки, взяті з консолі, коли я є залогіненим на steckoverflow');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_REFERER, 'http://stackoverflow.com/questions/tagged/javascript');
$html = curl_exec($ch);
curl_close($ch);
echo $html;

Я раніше майже не працював з curl, а тому не розумію чому stackoverflow не сприймає мій запит як належний, адже я ж начебто навіть куки видаю дійсні свої.

2

Re: Не виходить пропарсити мітки на Stackoverflow

Параметри з CURLOPT_COOKIEFILE і CURLOPT_COOKIEJAR тут лишні,коли ви вказуєте просто прямі CURLOPT_COOKIE.
Спробуйте звертатись без них.

3

Re: Не виходить пропарсити мітки на Stackoverflow

VTrim написав:

Параметри з CURLOPT_COOKIEFILE і CURLOPT_COOKIEJAR тут лишні,коли ви вказуєте просто прямі CURLOPT_COOKIE.
Спробуйте звертатись без них.

Те ж саме

4 Востаннє редагувалося ktretyak (02.04.2015 00:43:28)

Re: Не виходить пропарсити мітки на Stackoverflow

алілуя

$url = 'http://stackoverflow.com/questions/tagged/javascript+jquery';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); 
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER,
  [
    'Accept-Language:uk,en-US;q=0.8,en;q=0.6,ru;q=0.4',
    'Cache-Control:no-cache',
    'Connection:keep-alive',
    'Cookie:тут рядок з моїми куками',
    'Host:stackoverflow.com',
    'Pragma:no-cache',
    'Referer:http://stackoverflow.com/',
    'User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36'
  ]);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
$html = curl_exec($ch);
curl_close($ch);
echo $html;

Нарешті прорвало.

5 Востаннє редагувалося ktretyak (02.04.2015 00:45:38)

Re: Не виходить пропарсити мітки на Stackoverflow

Але проблема в тому, що статичні куки діють лише декілька раз, а потім вони змінюються. І якщо curl видає старі куки, то "викидає" із залогінення.

Тобто якимось чином потрібно видавати кожен раз ті куки, які ставить сервак.

6 Востаннє редагувалося VTrim (02.04.2015 08:56:31)

Re: Не виходить пропарсити мітки на Stackoverflow

Потрібно кожен раз робити POST запит на авторизацію (теж через курл) , при якому автоматом будуть встановлюватись нові куки.

Тут так робив
http://replace.org.ua/topic/3211/

Але може на стековерфлов і не вийде,пробуйте

7 Востаннє редагувалося ktretyak (02.04.2015 15:08:43)

Re: Не виходить пропарсити мітки на Stackoverflow

VTrim написав:

Потрібно кожен раз робити POST запит на авторизацію (теж через курл) , при якому автоматом будуть встановлюватись нові куки.

Тут так робив
http://replace.org.ua/topic/3211/

Але може на стековерфлов і не вийде,пробуйте

Та ні, якщо встановлені актуальні куки, то немає потреби за кожним разом авторизовуватись, тим більше на stackoverflow авторизація є сторонньою (через одну з найвідоміших соцмереж).

Я вирішив цю проблему так: за кожним запитом "вручну" перебираю заголовки, відбираю в них куки, зберігаю, а при новому запиті їх читаю зі свого файла й передаю. В такому разі все проходить без збоїв.

Але оскільки curl'у можна передавати параметр

curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');

то думаю що можливо є якісь налаштування, які дозволять автоматично це робити.

8

Re: Не виходить пропарсити мітки на Stackoverflow

Хм,я тестував,куки не збились протягом 12 годин.
Можливо там перевіряється іп,з якого заходите а у вас він динамічний ?

9 Востаннє редагувалося ktretyak (02.04.2015 15:21:44)

Re: Не виходить пропарсити мітки на Stackoverflow

VTrim написав:

Хм,я тестував,куки не збились протягом 12 годин.
Можливо там перевіряється іп,з якого заходите а у вас він динамічний ?

Так, він в мене динамічний, але спостерігаючи за куками, бачу що вони встановлюються приблизно кожних три хвилини.

Можливо це залежить від того куди саме ви ходите. Бо не залежно від авторизації stackoverflow дозволяє парсити ті ж самі мітки, але якщо по одній за раз, а не цілий ряд, наприклад,

http://stackoverflow.com/questions/tagged/javascript+jquery+css

10

Re: Не виходить пропарсити мітки на Stackoverflow

По ідеї куки мають автоматом записуватись і зчитуватись при записі,бо ж є COOKIEFILE COOKIEJAR,але до цього зчитування з файлу ви спочатку відправляєте свої заголовки HTTPHEADER,де постійно стоять ваші старі (вручну встановлені) куки,так?
Тож вони і відправляються першими.

11

Re: Не виходить пропарсити мітки на Stackoverflow

Ні, звичайно ж я це враховую і змінив вже свій код. Після довгих пошуків рішення я знайшов собі функцію get_web_page() десь на тому ж stackoverflow, трохи підлампічив її під себе, ну і дописав ще три функції:

<?php

function get_web_page( $url, $cookiesIn = '' )
{
  $options =
  [
      CURLOPT_RETURNTRANSFER => true,     // return web page
      CURLOPT_HEADER         => true,     //return headers in addition to content
      CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
      CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0',
      CURLOPT_COOKIEFILE => 'cookie_file.txt',
      CURLOPT_COOKIEJAR => 'cookie_jar.txt',
      CURLOPT_TIMEOUT        => 120,      // timeout on response
      CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
      CURLINFO_HEADER_OUT    => true,
      CURLOPT_SSL_VERIFYPEER => false,     // Disabled SSL Cert checks
      CURLOPT_COOKIE         => $cookiesIn
  ];

  $ch = curl_init( $url );
  curl_setopt_array( $ch, $options );
  $rough_content = curl_exec( $ch );
  $err     = curl_errno( $ch );
  $errmsg  = curl_error( $ch );
  $header  = curl_getinfo( $ch );
  curl_close( $ch );

  $header_content = substr($rough_content, 0, $header['header_size']);
  $body_content = trim(str_replace($header_content, '', $rough_content));
  $pattern = "#Set-Cookie:\\s+(?<cookie>[^=]+=[^;]*)#m"; 
  preg_match_all($pattern, $header_content, $matches); 
  $cookiesOut = implode("; ", $matches['cookie']);

  $header['errno']   = $err;
  $header['errmsg']  = $errmsg;
  $header['headers']  = $header_content;
  $header['content'] = $body_content;
  $header['cookies'] = $cookiesOut;
  
  return $header;
}

function http_parse_cookie( $str_cookies )
{
  $arr_coookies = explode('; ', $str_cookies);
  
  foreach($arr_coookies as $key => $cookie)
  {
    unset($arr_coookies[$key]);
    preg_match('#^([^=]+)=(.*)#', $cookie, $matches);
    
    if(isset($matches[1]))
      $arr_coookies[$matches[1]] = $matches[2];
  }
  return $arr_coookies;
}

function http_build_cookie( $arr_coookies )
{  
  foreach($arr_coookies as $key => $value)
  {
    $arr_coookies[$key] = "$key=$value";
  }
  return str_replace('; =', '', implode('; ', $arr_coookies) );
}

function get_content($url)
{
  $cookie_file = 'cookie_file.txt';
  
  $current_cookies = file_get_contents($cookie_file);
  
  $content = get_web_page($url, $current_cookies);
  
  $current_cookies = http_parse_cookie($current_cookies);
  $new_cookies = http_parse_cookie($content['cookies']);
  
  foreach($new_cookies as $key => $value)
  {
    $current_cookies[$key] = $value;
  }
  
  file_put_contents( $cookie_file, http_build_cookie($current_cookies) );

  return $content['content'];
}

Тепер можна один раз прописати налаштування у get_web_page() та встановити актуальні куки у файл cookie_file.txt.

Ну і потім вже можна викликати функцію get_content($url), яка повертає контент.

P.S. У функції http_build_cookie() є такий фрагмент

str_replace('; =', '', implode('; ', $arr_coookies) );

це невеличкий костиль, який мені було лінь вночі переписувати... він зараз потрібен, бо постійно у файлі куків чомусь залишається '; =' без відповідної куки.

Зараз проспався, то гляну що воно таке.

12 Востаннє редагувалося ktretyak (02.04.2015 15:57:16)

Re: Не виходить пропарсити мітки на Stackoverflow

Кому цікаво поглянути яку я статистику збираю, ось вона:
https://1933a544b9b651d3813e8de397efcd5a179e17e8.googledrive.com/host/0Bwk9euTxkxYUOFFUS29tSGJ4eXM/replace.org.ua/img/parse-stackoverflow-tags.png
Це лише "звіт" що робить скрипт, а він записує в базу SQLite ще й кількість по кожній мітці. В даному разі мене цікавить статистика найбільш рейтинговіших рядів міток.

P.S. Хто надумає теж парсити якийсь сайт, то не паліть контору - виставте хоча б sleep(3) в циклі

13 Востаннє редагувалося ktretyak (03.04.2015 04:07:42)

Re: Не виходить пропарсити мітки на Stackoverflow

Оце так! Виявляється на stackoverflow можна створювати власні запити до їхньої бази та ще й завантажувати ці дані в CSV-форматі! =)

А я тут велосипедю.

Подякували: 0xDADA11C71