<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: Пример скачивания записи ЖЖ с развёрнутыми комментариями]]></title>
		<link>https://forum.script-coding.com/viewtopic.php?id=13930</link>
		<atom:link href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=13930&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: Пример скачивания записи ЖЖ с развёрнутыми комментариями».]]></description>
		<lastBuildDate>Tue, 10 Jul 2018 17:55:27 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: AHK: Пример скачивания записи ЖЖ с развёрнутыми комментариями]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=126920#p126920</link>
			<description><![CDATA[<p>Еще можно качать запись в виде мобильной версии, для которой стили не меняются: <br /></p><div class="codebox"><pre><code>https://m.livejournal.com/read/user/miss-tramell/1564043</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (DD)]]></author>
			<pubDate>Tue, 10 Jul 2018 17:55:27 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=126920#p126920</guid>
		</item>
		<item>
			<title><![CDATA[AHK: Пример скачивания записи ЖЖ с развёрнутыми комментариями]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=126918#p126918</link>
			<description><![CDATA[<p>Скрипт скачивает запись ЖЖ с подстраницами комментариев (не переходя по трэдам — свёрнутым комментариям) и извлекает запись и информацию о смещении каждого комментария —</p><div class="codebox"><pre><code>https://miss-tramell.livejournal.com/1564043.html?page=%pg_num%&amp;style=mine</code></pre></div><p>* [Поскольку от журнала к журналу стили имеют разный код, скачивание должно происходить в стиле одного журнала (style=mine), через который скрипт логинится в ЖЖ. При этом комментарии в его стиле должны иметь не JS, а HTML код].</p><p>Затем загружаются комментарии в JSON-виде (доступные, даже когда владелец журнала закрыл их отображение у себя) — </p><div class="codebox"><pre><code>https://www.livejournal.com/__rpc_get_thread?journal=miss-tramell&amp;itemid=1564043&amp;flat=&amp;skip=&amp;media=&amp;expand_all=1&amp;page=%pg_num%</code></pre></div><p>парсятся и объединяются с записью и инфой о смещениях комментов, в итоге получая развёрнутые кооментарии сплошным текстом.</p><div class="codebox"><pre><code>#MaxMem 500
SetBatchLines -1
#SingleInstance Force


;----------------------------------------------------------------------
proxy := &quot;109.207.62.69:8080&quot;
ProxyOrNot:=0 ; задействовать прокси, или нет
LoginOrNot:=1 ; логиниться, или нет
ComObjError(false)
HTTP := ComObjCreate(&quot;WinHTTP.WinHTTPRequest.5.1&quot;)
login    := &quot;**********&quot;
password := &quot;**********&quot;
path = %A_ScriptDir%\
SplashBC = 00B0EA
;----------------------------------------------------------------------


loop_link = https://miss-tramell.livejournal.com/1564043.html

RegExMatch(loop_link, &quot;s)(https?://(.*?)\.livejournal\.com/)?(\d+)\.html(\?style=mine)?&quot;, match)
lj_uname := match2
lj_pgnum := match3

dest_path = %path%%lj_pgnum%.html
if (NOT FileExist(dest_path))
   Gosub, dwn
else
{
   msgbox Файл существует`n%dest_path%
   ExitApp
}
dwn:

If not (LoginMode == 1)  ;при первом запуске один раз:
{
   If LoginOrNot   ;если надо логиниться
      GoSub, login
   LoginMode = 1
}

; скачивание записи с подстраницами комментариев
n := 1, LJ_Tmp_Pages :=&quot;&quot;, cmtCount :=&quot;&quot;
;HTTP := ComObjCreate(&quot;WinHTTP.WinHTTPRequest.5.1&quot;)
loop
{
   HTTP.Open(&quot;GET&quot;, &quot;https://&quot; lj_uname &quot;.livejournal.com/&quot; lj_pgnum &quot;.html?page=&quot; n &quot;&amp;style=mine&quot;, true)
   If ProxyOrNot
      HTTP.SetProxy(2, proxy)
   GoSub, SetRequestHeader
   HTTP.Send()
   HTTP.WaitForResponse()
   ResponseText := HTTP.ResponseText

   LJ_Tmp_Pages .= &quot;`n&quot; ResponseText

   If A_Index = 1
   {
      cmtCount := RegExReplace(ResponseText, &quot;s)^.*&lt;a [^&gt;]*\.html\?page=(\d+)(&amp;style=mine)?(#comments)?&#039;&gt;(&lt;b&gt;)?(\[)?\1(\])?(&lt;/b&gt;)?&lt;/a&gt;.*?$&quot;, &quot;$1&quot;)
      LjPost := RegExReplace(ResponseText, &quot;s).*?(&lt;div id=&quot;&quot;content&quot;&quot;&gt;.*?)&lt;div class=&quot;&quot;quickreply&quot;&quot; id=&quot;&quot;ljqrtentrycomment&quot;&quot;.*&quot;, &quot;$1&quot;)
      LjPost := RegExReplace(LjPost, &quot;s)^(.*&lt;div class=&quot;&quot;asset-tags&quot;&quot;&gt;.*?&lt;/div&gt;).*&quot;, &quot;$1&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&lt;/div&gt;`n&quot;)
      PostTitle := RegExReplace(ResponseText, &quot;s).*?&lt;title&gt;(.*?)&lt;/title&gt;.*&quot;, &quot;$1&quot;)
      PostTitle := RegExReplace(PostTitle, &quot;\R+\s*|\s+$&quot;, &quot;&quot;)
      If NOT InStr(ResponseText, &quot;id=&quot;&quot;ljcmt&quot;) or NOT ResponseText~=&quot;\.html\?page=\d+&amp;style=mine?(#comments)?&#039;&gt;&lt;b&gt;\[\d+\]&lt;/b&gt;&quot;
         break
   }

   if (n &gt;= cmtCount)
      break
   n+=1 ; смещение по offset
}

ResponseText =
CmtThreads =

loop
{
   ;скачивание страниц комментов в JSON формате
   get_thread := &quot;https://www.livejournal.com/__rpc_get_thread?journal=&quot; lj_uname &quot;&amp;itemid=&quot; lj_pgnum &quot;&amp;flat=&amp;skip=&amp;media=&amp;expand_all=1&amp;page=&quot; A_Index
   HTTP.Open(&quot;GET&quot;, get_thread, true)
   GoSub, SetRequestHeader
   HTTP.Send()
   HTTP.WaitForResponse()
   ResponseText := HTTP.ResponseText

   StrReplace(ResponseText, &quot;{&quot;&quot;shown&quot;&quot;:&quot;,, CmtCountFromPage)

   If A_Index = 1
      cmtCountAll := RegExReplace(ResponseText, &quot;s)^\{&quot;&quot;replycount&quot;&quot;:(\d+).*$&quot;, &quot;$1&quot;)

   If NOT InStr(ResponseText, &quot;{&quot;&quot;replycount&quot;&quot;:&quot;) or (CmtCountFromPage = 0)
      break

   Gosub, JSON_Parse

   CountFromPage += CmtCountFromPage

   ResponseText =
   If (CountFromPage &gt; cmtCountAll)
      break
}

CmtThreads := RegExReplace(CmtThreads, &quot;s)&lt;a [^&gt;]*&gt;&lt;img [^&gt;]*&gt;&lt;/a&gt;\n&lt;div [^&gt;]*&gt;&lt;img [^&gt;]*&gt;&amp;nbsp.&lt;a title=&quot;&quot;&quot;&quot; href=&quot;&quot;&quot;&quot;&gt;&lt;/a&gt; – &lt;a [^&gt;]*&gt;&lt;/a&gt;&amp;nbsp.&lt;/div&gt;\n(&lt;div [^&gt;]*&gt;&lt;b&gt;\(Удалённый комментарий\)&lt;/b&gt;&lt;/div&gt;)&quot;, &quot;$1&quot;)

match := &quot;&quot;, Pos := 1
While ( Pos := RegExMatch(LJ_Tmp_Pages, &quot;s)(&lt;div\s+id=&quot;&quot;ljcmt)(\d+)(&quot;&quot; style=&quot;&quot;margin-left: ?\d+px;?&quot;&quot;)&quot;, match, Pos + StrLen(match)) )
    StringReplace, CmtThreads, CmtThreads, &lt;div id=&quot;ljcmt%match2%&quot;, %match1%%match2%%match3%, All

   GoSub, Sklonenie
   Gosub, htmlcode


fileappend, %htmlcode%`n`n%LjPost%`n`n`n, %dest_path%, UTF-8
fileappend, &lt;center&gt;&lt;h2&gt;%CountFromPage%&lt;/h2&gt;&lt;/center&gt;`n`n`n%CmtThreads%`n`n&lt;/body&gt;`n&lt;/html&gt;`n`n, %dest_path%, UTF-8

CountFromPage =
cmtCountAll =
CmtCountFromPage =
LjPost =
PostTitle =
cmtCount =
lj_pgnum =
lj_uname =
LJ_Tmp_Pages =
CmtThreads =
ResponseText =
LJ_Tmp_Pages =
match =
match1 =
match2 =
match3 =
match4 =
loop_link =
str =
unit =

return

Sklonenie:
   unit := CountFromPage - (CountFromPage // 100 * 100)
   unit &gt; 20 ? dPart := unit // 10 * 10 : dPart := 0
   str := (unit == 1 + dPart) ? &quot;комментарий&quot; : (unit &gt; 1 + dPart &amp;&amp; unit &lt; 5 + dPart) ? &quot;комментария&quot; : &quot;комментариев&quot;
   CountFromPage := CountFromPage &quot; &quot; str
return

JSON_Parse:
obj := JSON.Parse(ResponseText)
keys =
(
userpic
uname
commenter_journal_base
dtalkid
upictitle
article
ctime
deleted
parent
subject
striked
userhead_url
dname
)

for k, v in obj.comments  {
   Loop, parse, keys, `n, `r
      %A_LoopField%%k% := SearchKey(v, A_LoopField)

   if (userpic%a_index% = &quot;&quot;)
      userpic%a_index% := &quot;https://l-stat.livejournal.net/img/userpics/userpic-user.png?v=15821&quot;
   if (striked%a_index% = &quot;1&quot;)
      dname%a_index% := &quot;&lt;s&gt;&quot; dname%a_index% &quot;&lt;/s&gt;&quot;
   if (deleted%a_index% = &quot;1&quot;)
   {
      userpic%a_index% =
      article%a_index% := &quot;&lt;b&gt;(Удалённый комментарий)&lt;/b&gt;&quot;
   }
   ctime%a_index% := RegExReplace(ctime%a_index%, &quot;s) UTC&quot;, &quot;&quot;)

   CmtThreads .= &quot;`n&lt;div id=&quot;&quot;ljcmt&quot; dtalkid%a_index% &quot;&quot;&quot; class=&quot;&quot;comment&quot;&quot;&gt;&lt;a name=&quot;&quot;&quot; dtalkid%a_index% &quot;&quot;&quot;&gt;&lt;/a&gt;`n&lt;a href=&quot;&quot;#&quot; parent%a_index% &quot;&quot;&quot;&gt;&lt;img class=&quot;&quot;img&quot;&quot; title=&quot;&quot;&quot; upictitle%a_index% &quot;&quot;&quot; src=&quot;&quot;&quot; userpic%a_index% &quot;&quot;&quot;&gt;&lt;/a&gt;`n&lt;div class=&quot;&quot;info&quot;&quot;&gt;&lt;img class=&quot;&quot;userhead_url&quot;&quot; src=&quot;&quot;&quot; userhead_url%a_index% &quot;&quot;&quot;&gt;&amp;nbsp;&lt;a title=&quot;&quot;&quot; uname%a_index% &quot;&quot;&quot; href=&quot;&quot;&quot; commenter_journal_base%a_index% &quot;&quot;&quot;&gt;&quot; dname%a_index% &quot;&lt;/a&gt; – &lt;a href=&quot;&quot;https://&quot; lj_uname &quot;.livejournal.com/&quot; lj_pgnum &quot;.html?thread=&quot; dtalkid%a_index% &quot;#t&quot; dtalkid%a_index% &quot;&quot;&quot;&gt;&quot; ctime%a_index% &quot;&lt;/a&gt;&amp;nbsp;&quot; subject%a_index% &quot;&lt;/div&gt;`n&lt;div class=&quot;&quot;content&quot;&quot;&gt;&quot; article%a_index% &quot;&lt;/div&gt;`n&lt;/div&gt;`n&quot;
}
return

login:
SplashImage,, y-2 x60 w40 h14 M C11 ZH0 ZW0 ZX1 ZY1 B1 CTffffff CW%SplashBC% FM8 FS6 WM600 WS400,, login
;--------------------------------------------
;Авторизация:
;--------------------------------------------
HTTP.Open(&quot;GET&quot;, &quot;https://www.livejournal.com/login.bml&quot;, true)
If ProxyOrNot
   HTTP.SetProxy(2, proxy)
GoSub, SetRequestHeader
HTTP.Send()
HTTP.WaitForResponse()
RegexMatch(HTTP.ResponseText, &quot;s)name=&quot;&quot;lj_form_auth&quot;&quot; value=&quot;&quot;([^&quot;&quot;]*)&quot;&quot;&quot;, match)
PostData := &quot;lj_form_auth=&quot; match1 &quot;&amp;ref=&amp;returnto=%2F&amp;user=&quot; login &quot;&amp;password=&quot; password &quot;&amp;remember_me=1&amp;action%3Alogin=&quot;
StringReplace, PostData, PostData, :, `%3A, All

HTTP.Open(&quot;POST&quot;, &quot;https://www.livejournal.com/login.bml&quot;, true)
If ProxyOrNot
   HTTP.SetProxy(2, proxy)
HTTP.SetRequestHeader(&quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot;)
GoSub, SetRequestHeader
HTTP.Send(PostData)
HTTP.WaitForResponse()
If !Instr(HTTP.ResponseText, &quot;--&gt;Выйти&lt;!--&quot;)
;   msgbox Log On!
;Else
   msgbox, LogOn Failed!
ResponseText =
;--------------------------------------------
SplashImage, OFF
Return

SetRequestHeader:
HTTP.SetRequestHeader(&quot;User-Agent&quot;, &quot;Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko)&quot;)
HTTP.SetRequestHeader(&quot;Pragma&quot;, &quot;no-cache&quot;)
HTTP.SetRequestHeader(&quot;Cache-Control&quot;, &quot;no-cache, no-store&quot;)
HTTP.SetRequestHeader(&quot;If-Modified-Since&quot;, &quot;Sat, 1 Jan 2000 00:00:00 GMT&quot;)
return

htmlcode:
htmlcode=
(
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;%PostTitle%&lt;/title&gt;
&lt;meta http-equiv=Content-Type content=&quot;text/html; charset=UTF-8&quot;&gt;
&lt;style type=&quot;text/css&quot;&gt; &lt;!--
body {
  Xwidth: 100`%;
  margin-bottom: 10`% !important;
}
.comment {
  Xbackground-color:#EEEEEE;
  padding: 20px 20px 0px 20px;
}
.content {
  width: 95`%;
  padding: 10px 20px 20px 60px;
}
.comment .img {
  float: left;
  width: 60px;
  Xheight: 60px;
  margin: 3px 10px 5px 0px;
}
.info {
  color:#767676;
  font-size:90`%;
}
.info a {
  font-weight:bold;
}
--&gt;&lt;/style&gt;

&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://l-stat.livejournal.net/??voxhtml/base.css,voxhtml/default/screen.css,voxhtml/woodcut/screen.css,voxhtml/ljextras.css,voxhtml/widget-threeposts.css,voxhtml/widget-ramblerpartner.css?v=1530780559&quot; media=&quot;all&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
`n`n`n`n
)
Return

SearchKey(obj, key)  {
   for k, v in obj  {
      if (k = key)
         Return v
      
      if IsObject(v)  {
         res := SearchKey(v, key)
         if (res != &quot;&quot;)
            Return res
      }
   }
}

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.(&quot;(&quot; JsonString &quot;)&quot;)
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) &lt;&lt; !!A_IsUnicode, 0)
      DllCall(&quot;GetTempFileName&quot;, Str, A_Temp, Str, &quot;AHK&quot;, UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      &lt;component&gt;
      &lt;public&gt;&lt;method name=&#039;eval&#039;/&gt;&lt;/public&gt;
      &lt;script language=&#039;JScript&#039;&gt;&lt;/script&gt;
      &lt;/component&gt;
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet(&quot;script:&quot; . tmpFile), &quot;eval&quot; )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == &#039;[object Array]&#039;
         }
      )
      JS.(&quot;delete ActiveXObject; delete GetObject;&quot;)
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = &quot;&quot;)
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}
</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (DD)]]></author>
			<pubDate>Tue, 10 Jul 2018 16:53:03 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=126918#p126918</guid>
		</item>
	</channel>
</rss>
