Capturador de enlaces Series

Pregunta Sin Miedo no te cortes cualquier cosa para empezar - Autoit se comienza facilmente.Para Ordenes o Comandos sueltos. Ver nota como preguntar.
Responder
jamaro
Hacker del Foro
Mensajes: 253
Registrado: 03 Nov 2010, 23:04

Capturador de enlaces Series

Mensaje por jamaro »

Hola a tod@s:

Nunca sé si este tipo de mensaje va en este sub-foro, pero lo dejo aquí y si algún administrador lo considera oportuno que lo mueva donde corresponda.

Hace unas semanas me comentaron unos amigos que utilizan la página Series Yonkis para bajarse capítulos de sus series favoritas. Me comentaron que era un poco incómodo tener que navegar por la página para obtener los enlaces, ya que hay que pinchar en varios enlaces hasta llegar al deseado.
Enseguida me vino a la mente: Operación repetitiva = Solución con Autoit

Me puse manos a la obra, y a ratos he conseguido hacer algo que funciona (sin depurar, claro).

Los pasos a seguir son:
1º Indicar la URL de la serie que buscamos en el formato: http://www.seriesyonkis.com/serie/NOMBRESERIE. Este enlace debe coincidir con el que se utiliza en la página, así que mejor buscar primero el nombre de la serie porque suele tener guiones bajos.

2º Pulsar al botón "Capturar"

Tras hacer esto, el programa empieza a navegar por la página y subpáginas, recogiendo los enlaces de TODOS los capítulos y temporadas de la serie seleccionada. Lo muestra en la pantalla, más que nada para que el usuario sepa que el programa está trabajando, porque el proceso no es demasiado rápido y si no se ve actividad puede parecer que está parado.
Todos los datos recogidos se guardan en un archivo TXT con el nombre de la serie y la fecha y hora actual.
Posteriormente se puede utilizar ese archivo de texto en un Gestor de Descargas (tipo JDownloader) que detectará los enlaces e irá descargando.

Hay que tener en cuenta que los enlaces obtenidos son de la propia página de Series Yonkis, que posteriormente reenviar automáticamente a la del servidor (Megaupload, FileServer,...) (De momento no sé como obtener directamente ese enlace)

También suele ocurrir que tras hacer varias peticiones a los enlaces (ya desde el Gestor de Descargas), en lugar de reenviar al servidor, aparece una pantalla de la propia página de Series Yonkis intentando comprobar "que somos humanos" y haya que rellenar un captcha.

El programa tiene una parte preparada para hacer un filtrado por servidor y uploader, ya que mis amigos me comentaron que sería interesante que mostrara sólo los enlaces de un servidor y/o uploader concreto.
Dando valor a $FiltroServ y $FiltroUploader se obtendrá la lista filtrada, pero lo que pretenden mis amigos es que si además no existe ese Servidor y/o Uploader, guarde el primer enlace de la lista. Esto, de momento, se lo dejo que lo hagan ellos desde una hoja de cálculo como Calc (LibreOffice) o Excel, ya que es muy fácil hacerlo con los autofiltros.

En cuanto al código, comentar que al principio me empeñé en hacerlo con _IECreate y obteniendo objetos DIV y tags, recorriendo las tablas, filas y celdas, pero, aunque me llegó a funcionar era lentísimo, y volví al método que estoy utilizando en todas mis aplicaciones que buscan en páginas web, con las Expresiones Regulares.

¡Un saludo y Feliz Navidad!

Pongo el código, aunque se puede descargar más abajo:

Código: Seleccionar todo

;=========================================================================
; Capturador Enlaces Series Yonkis
; Programa para la captura de enlaces de capítulos de una serie de la página SeriesYonkis.com
; jamaro Dic-2011
;
;	Introduciendo la URL de una serie en el formato: http://www.seriesyonkis.com/serie/NOMBRESERIE
;	el programa recorre todas las páginas de todos los capítulos de la serie seleccionada
;	y guarda en un archivo de texto los datos y enlaces de descarga de cada capítulo
;	Posteriormente el archivo generado se puede utilizar en gestores de descarga
;	o, por ejemplo en Calc (LibreOffice) o Excel (Microsoft) filtrar los resultados
;	por el servidor o uploader deseado.
;=========================================================================

#Region Notas
#cs
- Sobre el programa:
	El control Edit que muestra los resultados tiene una capacidad máxima de unos 64 Kb, por lo que en series con muchos capítulos/enlaces puede que no se muestre completo
- Sobre la captura de datos:
	Algunos enlaces que comentan cómo obtener enlaces de SeriesYonkis, pero que están desactualizados porque la web ha cambiado su formato.
		http://www.carloscapote.com/informatica-y-otras-fricadas/como-hacer-una-copia-de-seguridad-de-la-base-de-datos-de-enlaces-de-seriesyonkis-com-for-casidummies/
		http://pastebin.com/Y6f0rZaF
#ce
#EndRegion Notas

#Region Includes

#include <IE.au3>
#include <Array.au3>

; --- Para GUI ---
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GuiEdit.au3>
; ---
#EndRegion Includes

#Region Variables
; --- Variables
Opt("MustDeclareVars",1)

Global $depuracion=1

Global $ProgNombre="Capturador SeriesYonkis"
Global $ProgAutor="jamaro"
Global $ProgVers="Beta 1.0"
Global $ProgVersFecha="20111224"
Global $TituloGUI=$ProgNombre & " ("& $ProgAutor &") " & $ProgVers & " " & $ProgVersFecha


; --- Variables Función CapturarEnlaces()
Global $URLSerie, $NombreSerie,$WebSerie
Global $CapNum, $CapNom, $CapFecha, $CapIdioma, $CapNota
Global $CapURL
Global $ListadoCapitulos
Global $NombreArchivo, $file
Global $WebEnlaceDescarga,$CapEnlaceServidor

; --- Variables Función ListadoEnlacesCapitulo()
Global $FiltroServ, $FiltroUploader
Global $WebCapitulo, $DatosCapitulo
Global $Contador=0
Global $mListado[1][10]
Global $Enlace, $CapTitulo, $CapTemporada, $CapNumero, $Servidor, $Idioma, $Subtitulos, $Calidad, $Notas, $Uploader
#EndRegion Variables


#Region GUI
; --- GUI
Global $GUI_Ppal, $et1, $inURLSerie, $bCapturar, $etAvisos, $edResultados
Global $nMsg

;$GUI_Ppal = GUICreate($TituloGUI, 393, 351, 192, 114)	; Para reemplazar dentro del código generado con KODA GUI
#Region ### START Koda GUI section ###
$GUI_Ppal = GUICreate($TituloGUI, 393, 351, 192, 114)
$et1 = GUICtrlCreateLabel("Introduzca la URL de la serie", 10, 15, 141, 17)
$inURLSerie = GUICtrlCreateInput("inURLSerie", 10, 50, 290, 21)
$bCapturar = GUICtrlCreateButton("Capturar", 310, 50, 70, 25)
$etAvisos = GUICtrlCreateLabel("Avisos", 10, 100, 370, 17)
$edResultados = GUICtrlCreateEdit("", 10, 130, 370, 201, BitOR($GUI_SS_DEFAULT_EDIT,$ES_READONLY))
GUICtrlSetData(-1, "Edit1")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

; Modificación del GUI
GUICtrlSetData($et1,"Introduzca la URL de la serie con el formato http://www.seriesyonkis.com/serie/NOMBRESERIE")
GUICtrlSetData($inURLSerie,"http://www.seriesyonkis.com/serie/acusados")
GUICtrlSetData($etAvisos,"En espera...")
GUICtrlSetColor($etAvisos,0x0000ff)
GUICtrlSetData($edResultados,"En espera (nada que mostrar)")
GUICtrlSetTip($bCapturar, "Capturar los enlaces de todos los capítulos")


While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $bCapturar
			CapturarEnlaces()
			GUICtrlSetData($etAvisos,"En espera...")
	EndSwitch
WEnd
#EndRegion GUI

#Region =========================== FUNCIONES ===========================

Func CapturarEnlaces()
;	-------------------------------------------------------------------------------------------------------------------
;	CaputarEnlaces()
;	De la página de la serie se obtiene el listado de todos los capítulos de las distintas temporadas
;	-------------------------------------------------------------------------------------------------------------------


MsgBox(0,"Aviso","Se va a proceder a la lectura de páginas de enlaces de capítulos." & @CRLF & @CRLF & "Esta operación puede tardar varios minutos, en función de la cantidad de capítulos que tenga la serie.")
GUICtrlSetData($etAvisos,"Capturando enlaces ...")

$URLSerie=guictrlread($inURLSerie)
$NombreSerie=StringRegExp($URLSerie,'http://www.seriesyonkis.com/serie/(.*)',3)

; Se crea un archivo de texto cuyo nombre es el nombre de la serie y la fecha y hora actual
	$NombreArchivo=$NombreSerie[0] & "_" & @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & ".txt"
	$file = FileOpen($NombreArchivo, 1)	; Abre archivo para guardar los datos

; Comprueba si el archivo está abierto para escribir
	If $file = -1 Then
		MsgBox(0, "Error", "No ha sido posible abrir el archivo.")
		Exit
	EndIf

; Escribe la cabecera de resultados en el archivo de texto y en el Edit del GUI
	FileWriteLine($file, "Temporada" & @TAB & "Capítulo" & @TAB & "Título" & @TAB & "Enlace descarga" & @TAB & "Servidor" & @TAB & "Idioma" & @TAB & "Subtitulos" & @TAB & "Calidad" & @TAB & "Notas" & @TAB & "Uploader" & @CRLF)
;~ 	FileWriteLine($file, "--------------------------------------------------------------------------------------------------------------------------------------------------------" & @CRLF)

	GUICtrlSetData($edResultados,"Temporada" & @TAB & "Capítulo" & @TAB & "Título" & @TAB & "Enlace descarga" & @TAB & "Servidor" & @TAB & "Idioma" & @TAB & "Subtitulos" & @TAB & "Calidad" & @TAB & "Notas" & @TAB & "Uploader" & @CRLF)
	_GUICtrlEdit_AppendText($edResultados,"--------------------------------------------------------------------------------------------------------------------------------------------------------" & @CRLF)


; Se obtiene, mediante expresiones regulares, el listado de capítulos

	$WebSerie=_INetGetSourceEx($URLSerie)
	$ListadoCapitulos=StringRegExp($WebSerie,'(?s)<td.*?<a href="(.*?)".*?<strong>(.*?)</strong> - (.*?)</a>.*?<td>(.*?)</td>.*?title="(.*?)".*?<td class="score">(.*?)</td>',3)
;~ 	_ArrayDisplay($ListadoCapitulos)

	Local $GruposRegExp=6	; Número de grupos obtenidos mediante expresión regular

	For $i=0 to UBound($ListadoCapitulos)-1 step $GruposRegExp	; Al obtener con Expresión Regular una matriz con varios grupos, For se hace con Step
		$CapURL=$ListadoCapitulos[$i]
		$CapNum=$ListadoCapitulos[$i+1]
		$CapNom=$ListadoCapitulos[$i+2]
		$CapFecha=$ListadoCapitulos[$i+3]
		$CapIdioma=$ListadoCapitulos[$i+4]
		$CapNota=$ListadoCapitulos[$i+5]
		_cw($CapNum & @TAB & $CapNom & @TAB & $CapURL & @TAB & $CapFecha & @TAB & $CapIdioma & @TAB & $CapNota)

		GUICtrlSetData($etAvisos,"Capturando enlaces del capítulo ("& ($i/$GruposRegExp)+1 &"/"&(UBound($ListadoCapitulos)/$GruposRegExp) &")")
			_cw("$i("& $i/$GruposRegExp &"/"&(UBound($ListadoCapitulos)/$GruposRegExp)-1 &") URL: " & $CapURL & @CRLF)

; -------------------------------------
; Si se desea filtrar por Servidor y/o Uploader
		$FiltroServ=""
		$FiltroUploader=""

; Se obtiene, mediante expresiones regulares, el listado de enlaces de servidores del capítulo
		$WebCapitulo=_INetGetSourceEx("http://www.seriesyonkis.com"&$CapURL)
		$WebCapitulo=StringRegExp($WebCapitulo,'(?s)Descarga directa(.*?)Compra las temporadas de la serie',3)	; Se selecciona sólo la parte de la tabla de Descargas (obviando la de Reproducir)
		$DatosCapitulo=StringRegExp($WebCapitulo[0],'(?s)<td class="episode-server-img">.*?<a href="(.*?)".*?title="Descargar (.*?) (\d*?)x(\d*?)".*?<span class="server (.*?)".*?title="(.*?)".*?title="(.*?)".*?title="(.*?)".*?<li>(.*?)</li>.*?<td class="episode-uploader">(.*?)</td>',3)

		Local $GruposRegExpCap=10	; Número de grupos obtenidos mediante expresión regular

		For $x=0 to UBound($DatosCapitulo)-1 Step $GruposRegExpCap	; Al obtener con Expresión Regular una matriz con varios grupos, For se hace con Step
			$Enlace=$DatosCapitulo[$x]
			$CapTitulo=$DatosCapitulo[$x+1]
			$CapTemporada=$DatosCapitulo[$x+2]
			$CapNumero=$DatosCapitulo[$x+3]
			$Servidor=$DatosCapitulo[$x+4]
			$Idioma=$DatosCapitulo[$x+5]
			$Subtitulos=$DatosCapitulo[$x+6]
			$Calidad=$DatosCapitulo[$x+7]
			$Notas=StringRegExpReplace($DatosCapitulo[$x+8],"[\r|\n]"," ")	; Reemplaza saltos de línea @CR y @LF por espacio
			$Uploader=$DatosCapitulo[$x+9]

			; Para el filtrado se utiliza StringRegExp porque StringInStr no funciona cuando uno de los valores de los filtros es ""
			If StringRegExp($Servidor,$FiltroServ) And StringRegExp($Uploader,$FiltroUploader) Then
				ReDim $mListado[$Contador+1][10]
				$mListado[$Contador][0]="http://www.seriesyonkis.com"&$Enlace
				$mListado[$Contador][1]=$CapTitulo
				$mListado[$Contador][2]=$CapTemporada
				$mListado[$Contador][3]=$CapNumero
				$mListado[$Contador][4]=$Servidor
				$mListado[$Contador][5]=$Idioma
				$mListado[$Contador][6]=$Subtitulos
				$mListado[$Contador][7]=$Calidad
				$mListado[$Contador][8]=$Notas
				$mListado[$Contador][9]=$Uploader
;~ 			ConsoleWrite("Contador="&$Contador & @crlf)
;~ 			ConsoleWrite("Matriz="&Ubound($mListado) & @crlf)
;~ 			ConsoleWrite("---------------------------------------------" & @crlf)
			_cw("Página de descarga: " &$mListado[$Contador][0])
			$WebEnlaceDescarga=_INetGetSourceEx($mListado[$Contador][0])	; Carga la página de descarga
			$CapEnlaceServidor=StringRegExp($WebEnlaceDescarga,'<tr class="down"><td><a href="(.*?)" target="_blank">Descargar ahora</a>',3)
			_cw($CapEnlaceServidor[0] &@CRLF)
			FileWriteLine($file, $mListado[$Contador][2] & @TAB & $mListado[$Contador][3] & @TAB & $mListado[$Contador][1] & @TAB & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & @TAB & $mListado[$Contador][4] & @TAB & $mListado[$Contador][5] & @TAB & $mListado[$Contador][6] & @TAB & $mListado[$Contador][7] & @TAB & $mListado[$Contador][8] & @TAB & $mListado[$Contador][9] & @CRLF)
			;FileWriteLine($file, $mListado[$Contador][2] & "|" & $mListado[$Contador][3] & "|" & $mListado[$Contador][1] & "|" & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & "|" & $mListado[$Contador][4] & "|" & $mListado[$Contador][5] & "|" & $mListado[$Contador][6] & "|" & $mListado[$Contador][7] & "|" & $mListado[$Contador][8] & "|" & $mListado[$Contador][9] & @CRLF)
			_GUICtrlEdit_AppendText($edResultados,$mListado[$Contador][2] & @TAB & $mListado[$Contador][3] & @TAB & $mListado[$Contador][1] & @TAB & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & @TAB & $mListado[$Contador][4] & @TAB & $mListado[$Contador][5] & @TAB & $mListado[$Contador][6] & @TAB & $mListado[$Contador][7] & @TAB & $mListado[$Contador][8] & @TAB & $mListado[$Contador][9] & @CRLF)

			$Contador=$Contador+1
			EndIf
		Next

;~ 		_ArrayDisplay($mListado,"Descargas")	; Muestra la matriz de resultados


	Next

	FileClose($file)	; Cierra el archivo de texto donde se guardan los resultados

	msgbox(0,"Descarga Finalizada","Se ha creado el archivo " & $NombreArchivo & " con los capítulos y sus enlaces a descarga del servidor.")
	ShellExecute($NombreArchivo, "", @ScriptDir, "edit")

EndFunc ; CapturarEnlaces()



Func _INetGetSourceEx($s_URL, $bString = True)
	; Foro AutoitScrip.com: http://www.autoitscript.com/forum/topic/107500-inetgetsource-utf-8-problem/page__view__findpost__p__758141
    Local $sString = InetRead($s_URL, 1)
    Local $nError = @error, $nExtended = @extended
    If $bString Then $sString = BinaryToString($sString,4)
    Return SetError($nError, $nExtended, $sString)
EndFunc   ;==>_INetGetSourceEx

; Funciones _m y _cw para mostrar MsgBox y ConsoleWrite (en función del valor de $depuracíon)
	Func _m($msj="",$a=@ScriptLineNumber)
		If $depuracion=1 then msgbox(0,"Linea " & $a,$msj)
	EndFunc

	Func _cw($msj="",$a=@ScriptLineNumber)
		If $depuracion=1 then ConsoleWrite("[L:"&$a & "] " & $msj & @CRLF)
	EndFunc
#EndRegion =========================== FUNCIONES ===========================
Adjuntos
CapturadorSeriesYonkis_jamaro.zip
Código .au3 y Programa compilado .exe
(406.5 KiB) Descargado 158 veces
jamaro
Hacker del Foro
Mensajes: 253
Registrado: 03 Nov 2010, 23:04

Re: Capturador de enlaces Series

Mensaje por jamaro »

Y aprovecho para hacer una pregunta: ¿Cómo se puede hacer para detener o cerra el programa mientras se está ejecutando el proceso de lectura de las páginas? En mis pruebas, desde el propio SciTE lo detengo con Herramientas > Detener ejecución, pero supongo que se debería programar para que se bloqueara al cerrar el GUI o con un botón de Cancelar.

Saludos.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturador de enlaces Series

Mensaje por Ximorro »

¡Muy buen trabajo!

Respecto a tu pregunta puede que el GUI no responda porque el programa está realizando una tarea larga y no está en el bucle de comprobación de eventos.
Una manera de evitar esto es usar el modo OnEvent, en vez de el de bucle de mensajes. En modo OnEvent los eventos interrumpen el código, con lo que el botón de Salida funcionará sin bloqueos.
Eso sí, como estás interrumpiendo un proceso asegúrate de cerrar posibles archivos abiertos y cosas así.

Otro sistema sería poner HotKeys para salir. Un hotkey global (HotKeySet ()) seguramente funcionará, no sé si los locales GUISetAccelerators() tendrán el mismo problema que los eventos pero sospecho que sí, que sólo funcionarán sin bloqueos/retrasos con el modo OnEvent, pues al fin y al cabo GUISetAccelerators() lo que hace es disparar eventos.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
BasicOs
Site Admin
Mensajes: 2091
Registrado: 21 Nov 2006, 19:24
Ubicación: El Internet - (Canarias, España)
Contactar:

Re: Capturador de enlaces Series

Mensaje por BasicOs »

Hola,
Lo de pasar a hard-soft las páginas web tiene sus ventajas, también puede ser algo así en busqueda de ofertas de segundamano o comparador de precios. Incluso ideal si se pudiera automatizar en un form que luego pase a una función las busquedas directamente. Con lo que de cualquier página se puede tener la versión txt o en el programa. Por ejemplo buscar un iphone en una pagina como segundamano con un précio entre 100 y 150, pues que revise cada hora, y cuando haya algún movil en este intervalo me envie un mail. Solo es un ejemplo de cosas...
:smt023 :smt023
Aparte de formalizar/formatear más la función capturarenlaces() del programa:
yo haría el form un poco más grande un 40%, y pondría el separador como alternativa en el mismo form, que cada uno ponga el separador que quiera, el csv que es la coma , , , es muy habitual para importar a excel y bases de datos, mejor que el TAB.

Incluso dar una ruta por defecto y opción a cambiar la ruta de destino, hasta el portapapeles.

También en vez de grabar directamente puedes ir guardando los datos en una variable, y luego al acabar grabar de una vez en el archivo, así no hay que acceder tanto al disco, por optimizar.., puedes poner una función grabarendisco($variable,$fichero,$separador), y otra capturarenlaces() con un separador fijo

EDIT:

Lo ideal sería en vez de CapturadorSeriesYonkis_jamaro Capturador_jamaro o bien filtro_web_jamaro donde recogiendo la información desde un INI:
0-.Accederiamos a unas paginas con datos útiles y con texto no necesario.
1.- estarían los parámetros para recoger y limpiar datos -> varios campos (trozos de texto) desde cualquier web,
2.- y guardar estos campos en unas tablas (tipo excel, csv o db)
3.- y devolverlos de alguna manera (pantalla, mail, fichero, etc)
Salu22:)
Avatar de Usuario
Chefito
Profesional del Autoit
Mensajes: 2035
Registrado: 21 Feb 2008, 18:42
Ubicación: Albacete/Cuenca (España)

Re: Capturador de enlaces Series

Mensaje por Chefito »

Primeramente, enhorabuena por el código que has relizado. En un futuro cercano también me pondré con cosas de estas. Lo tengo aparcado. A ver si acabo la práctica de Skyline en java, y los exámenes, y después intentaré coger el autoit para realizar algo de esto :smt002 .

Mmmmm....el tema de intentar salir de bucles siempre ha sido algo peleagudo. La gran búsqueda de intentar emular multihilo en autoit. Como dice Ximorro puedes probar varias cosas. Habrá cosas que te resulten y otras que no....o te vayan bastante mal.

Yo ya he emulado alguna vez cosas como esta con unos resultados digamos aceptables :smt005 . Por ejemplo, al cancelar la búsqueda de texto en mi último gran script que buscaba textos en múltiples tipos de ficheros. Échale un vistazo si eso.

Además de las formas que ha dicho Ximorro, se me ocurren otras que he utilizado.

La mejor forma para hacerlo es como dice Ximorro, intentarlo por funciones eventos. Lo malo es que creo recordar que ha veces, según el bucle, no funciona bien (puede que esté equivocado. Es cuestión de probar).

Si te falla lo anterior, lo más facil, y ha veces lo más práctico es poner el trozo de código que pilla los eventos que te interesa dentro del bucle. Por ejemplo:

Código: Seleccionar todo

   $nMsg = GUIGetMsg()
   Switch $nMsg
		Case $GUI_EVENT_CLOSE
			FileClose($file)   ; Cierra el archivo de texto donde se guardan los resultados
			Exit
		Case $btCancelar
			ExitLoop(2)
	EndSwitch
$btCancelar es un botón para cancelar la captura al pulsarlo.
Esto lo metes en el segundo for (el más profundo), o incluso en el 2º y el 1º (o lo repites por tu código tantas veces como creas que sea necesario) para capturar los dos eventos que te interesan (cancelar y salir del script).
Pero como he dicho antes, aquí creo recordar también (que memoria la mía :smt005 :smt005 ) que puede que alguna vez fallase. Puede que alguna vez pulses y no enganche el evento. Pero casi siempre suele funcionar.

Te pongo otra forma de hacerlo. Un ejemplo con tu código y luego explico. Yo, alguna vez lo he utilizado:

Código: Seleccionar todo

;=========================================================================
; Capturador Enlaces Series Yonkis
; Programa para la captura de enlaces de capítulos de una serie de la página SeriesYonkis.com
; jamaro Dic-2011
;
;   Introduciendo la URL de una serie en el formato: http://www.seriesyonkis.com/serie/NOMBRESERIE
;   el programa recorre todas las páginas de todos los capítulos de la serie seleccionada
;   y guarda en un archivo de texto los datos y enlaces de descarga de cada capítulo
;   Posteriormente el archivo generado se puede utilizar en gestores de descarga
;   o, por ejemplo en Calc (LibreOffice) o Excel (Microsoft) filtrar los resultados
;   por el servidor o uploader deseado.
;=========================================================================

#Region Notas
#cs
- Sobre el programa:
   El control Edit que muestra los resultados tiene una capacidad máxima de unos 64 Kb, por lo que en series con muchos capítulos/enlaces puede que no se muestre completo
- Sobre la captura de datos:
   Algunos enlaces que comentan cómo obtener enlaces de SeriesYonkis, pero que están desactualizados porque la web ha cambiado su formato.
      http://www.carloscapote.com/informatica-y-otras-fricadas/como-hacer-una-copia-de-seguridad-de-la-base-de-datos-de-enlaces-de-seriesyonkis-com-for-casidummies/
      http://pastebin.com/Y6f0rZaF
#ce
#EndRegion Notas

#Region Includes

#include <IE.au3>
#include <Array.au3>

; --- Para GUI ---
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GuiEdit.au3>
; ---
#EndRegion Includes

#Region Variables
; --- Variables
Opt("MustDeclareVars",1)

Global $depuracion=1

Global $ProgNombre="Capturador SeriesYonkis"
Global $ProgAutor="jamaro"
Global $ProgVers="Beta 1.0"
Global $ProgVersFecha="20111224"
Global $TituloGUI=$ProgNombre & " ("& $ProgAutor &") " & $ProgVers & " " & $ProgVersFecha


; --- Variables Función CapturarEnlaces()
Global $URLSerie, $NombreSerie,$WebSerie
Global $CapNum, $CapNom, $CapFecha, $CapIdioma, $CapNota
Global $CapURL
Global $ListadoCapitulos
Global $NombreArchivo, $file
Global $WebEnlaceDescarga,$CapEnlaceServidor

; --- Variables Función ListadoEnlacesCapitulo()
Global $FiltroServ, $FiltroUploader
Global $WebCapitulo, $DatosCapitulo
Global $Contador=0
Global $mListado[1][10]
Global $Enlace, $CapTitulo, $CapTemporada, $CapNumero, $Servidor, $Idioma, $Subtitulos, $Calidad, $Notas, $Uploader
Global $Cancelar=False	;chefito
#EndRegion Variables


#Region GUI
; --- GUI
Global $GUI_Ppal, $et1, $inURLSerie, $bCapturar, $etAvisos, $edResultados
Global $nMsg

;$GUI_Ppal = GUICreate($TituloGUI, 393, 351, 192, 114)   ; Para reemplazar dentro del código generado con KODA GUI
#Region ### START Koda GUI section ###
$GUI_Ppal = GUICreate($TituloGUI, 393, 351, 192, 114)
$et1 = GUICtrlCreateLabel("Introduzca la URL de la serie", 10, 15, 141, 17)
$inURLSerie = GUICtrlCreateInput("inURLSerie", 10, 50, 290, 21)
$bCapturar = GUICtrlCreateButton("Capturar", 310, 50, 70, 25)
$etAvisos = GUICtrlCreateLabel("Avisos", 10, 100, 370, 17)
$edResultados = GUICtrlCreateEdit("", 10, 130, 370, 201, BitOR($GUI_SS_DEFAULT_EDIT,$ES_READONLY))
GUICtrlSetData(-1, "Edit1")
Global $btCancelar = GUICtrlCreateButton("Cancelar", 310, 20, 70, 25)	;chefito
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

; Modificación del GUI
GUICtrlSetData($et1,"Introduzca la URL de la serie con el formato http://www.seriesyonkis.com/serie/NOMBRESERIE")
GUICtrlSetData($inURLSerie,"http://www.seriesyonkis.com/serie/acusados")
GUICtrlSetData($etAvisos,"En espera...")
GUICtrlSetColor($etAvisos,0x0000ff)
GUICtrlSetData($edResultados,"En espera (nada que mostrar)")
GUICtrlSetTip($bCapturar, "Capturar los enlaces de todos los capítulos")


While 1
   $nMsg = GUIGetMsg()
   Switch $nMsg
      Case $GUI_EVENT_CLOSE
         Exit
	 Case $bCapturar
		 AdlibRegister("Cancelar",10)	;chefito
         CapturarEnlaces()
         GUICtrlSetData($etAvisos,"En espera...")
   EndSwitch
WEnd
#EndRegion GUI

#Region =========================== FUNCIONES ===========================

Func CapturarEnlaces()
;   -------------------------------------------------------------------------------------------------------------------
;   CaputarEnlaces()
;   De la página de la serie se obtiene el listado de todos los capítulos de las distintas temporadas
;   -------------------------------------------------------------------------------------------------------------------


MsgBox(0,"Aviso","Se va a proceder a la lectura de páginas de enlaces de capítulos." & @CRLF & @CRLF & "Esta operación puede tardar varios minutos, en función de la cantidad de capítulos que tenga la serie.")
GUICtrlSetData($etAvisos,"Capturando enlaces ...")

$URLSerie=guictrlread($inURLSerie)
$NombreSerie=StringRegExp($URLSerie,'http://www.seriesyonkis.com/serie/(.*)',3)

; Se crea un archivo de texto cuyo nombre es el nombre de la serie y la fecha y hora actual
   $NombreArchivo=$NombreSerie[0] & "_" & @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & ".txt"
   $file = FileOpen($NombreArchivo, 1)   ; Abre archivo para guardar los datos

; Comprueba si el archivo está abierto para escribir
   If $file = -1 Then
      MsgBox(0, "Error", "No ha sido posible abrir el archivo.")
      Exit
   EndIf

; Escribe la cabecera de resultados en el archivo de texto y en el Edit del GUI
   FileWriteLine($file, "Temporada" & @TAB & "Capítulo" & @TAB & "Título" & @TAB & "Enlace descarga" & @TAB & "Servidor" & @TAB & "Idioma" & @TAB & "Subtitulos" & @TAB & "Calidad" & @TAB & "Notas" & @TAB & "Uploader" & @CRLF)
;~    FileWriteLine($file, "--------------------------------------------------------------------------------------------------------------------------------------------------------" & @CRLF)

   GUICtrlSetData($edResultados,"Temporada" & @TAB & "Capítulo" & @TAB & "Título" & @TAB & "Enlace descarga" & @TAB & "Servidor" & @TAB & "Idioma" & @TAB & "Subtitulos" & @TAB & "Calidad" & @TAB & "Notas" & @TAB & "Uploader" & @CRLF)
   _GUICtrlEdit_AppendText($edResultados,"--------------------------------------------------------------------------------------------------------------------------------------------------------" & @CRLF)


; Se obtiene, mediante expresiones regulares, el listado de capítulos

   $WebSerie=_INetGetSourceEx($URLSerie)
   $ListadoCapitulos=StringRegExp($WebSerie,'(?s)<td.*?<a href="(.*?)".*?<strong>(.*?)</strong> - (.*?)</a>.*?<td>(.*?)</td>.*?title="(.*?)".*?<td class="score">(.*?)</td>',3)
;~    _ArrayDisplay($ListadoCapitulos)

   Local $GruposRegExp=6   ; Número de grupos obtenidos mediante expresión regular

   For $i=0 to UBound($ListadoCapitulos)-1 step $GruposRegExp   ; Al obtener con Expresión Regular una matriz con varios grupos, For se hace con Step
;~ 		Sleep(10)
		;chefito
		If $Cancelar Then
			 $Cancelar=False
			 ExitLoop
		EndIf
	  $CapURL=$ListadoCapitulos[$i]
      $CapNum=$ListadoCapitulos[$i+1]
      $CapNom=$ListadoCapitulos[$i+2]
      $CapFecha=$ListadoCapitulos[$i+3]
      $CapIdioma=$ListadoCapitulos[$i+4]
      $CapNota=$ListadoCapitulos[$i+5]
      _cw($CapNum & @TAB & $CapNom & @TAB & $CapURL & @TAB & $CapFecha & @TAB & $CapIdioma & @TAB & $CapNota)

      GUICtrlSetData($etAvisos,"Capturando enlaces del capítulo ("& ($i/$GruposRegExp)+1 &"/"&(UBound($ListadoCapitulos)/$GruposRegExp) &")")
         _cw("$i("& $i/$GruposRegExp &"/"&(UBound($ListadoCapitulos)/$GruposRegExp)-1 &") URL: " & $CapURL & @CRLF)

; -------------------------------------
; Si se desea filtrar por Servidor y/o Uploader
      $FiltroServ=""
      $FiltroUploader=""

; Se obtiene, mediante expresiones regulares, el listado de enlaces de servidores del capítulo
      $WebCapitulo=_INetGetSourceEx("http://www.seriesyonkis.com"&$CapURL)
      $WebCapitulo=StringRegExp($WebCapitulo,'(?s)Descarga directa(.*?)Compra las temporadas de la serie',3)   ; Se selecciona sólo la parte de la tabla de Descargas (obviando la de Reproducir)
      $DatosCapitulo=StringRegExp($WebCapitulo[0],'(?s)<td class="episode-server-img">.*?<a href="(.*?)".*?title="Descargar (.*?) (\d*?)x(\d*?)".*?<span class="server (.*?)".*?title="(.*?)".*?title="(.*?)".*?title="(.*?)".*?<li>(.*?)</li>.*?<td class="episode-uploader">(.*?)</td>',3)

      Local $GruposRegExpCap=10   ; Número de grupos obtenidos mediante expresión regular

      For $x=0 to UBound($DatosCapitulo)-1 Step $GruposRegExpCap   ; Al obtener con Expresión Regular una matriz con varios grupos, For se hace con Step
;~          Sleep(10)
		;chefito
		 If $Cancelar Then
			 $Cancelar=False
			 ExitLoop(2)
		EndIf
		 $Enlace=$DatosCapitulo[$x]
         $CapTitulo=$DatosCapitulo[$x+1]
         $CapTemporada=$DatosCapitulo[$x+2]
         $CapNumero=$DatosCapitulo[$x+3]
         $Servidor=$DatosCapitulo[$x+4]
         $Idioma=$DatosCapitulo[$x+5]
         $Subtitulos=$DatosCapitulo[$x+6]
         $Calidad=$DatosCapitulo[$x+7]
         $Notas=StringRegExpReplace($DatosCapitulo[$x+8],"[\r|\n]"," ")   ; Reemplaza saltos de línea @CR y @LF por espacio
         $Uploader=$DatosCapitulo[$x+9]

         ; Para el filtrado se utiliza StringRegExp porque StringInStr no funciona cuando uno de los valores de los filtros es ""
         If StringRegExp($Servidor,$FiltroServ) And StringRegExp($Uploader,$FiltroUploader) Then
            ReDim $mListado[$Contador+1][10]
            $mListado[$Contador][0]="http://www.seriesyonkis.com"&$Enlace
            $mListado[$Contador][1]=$CapTitulo
            $mListado[$Contador][2]=$CapTemporada
            $mListado[$Contador][3]=$CapNumero
            $mListado[$Contador][4]=$Servidor
            $mListado[$Contador][5]=$Idioma
            $mListado[$Contador][6]=$Subtitulos
            $mListado[$Contador][7]=$Calidad
            $mListado[$Contador][8]=$Notas
            $mListado[$Contador][9]=$Uploader
;~          ConsoleWrite("Contador="&$Contador & @crlf)
;~          ConsoleWrite("Matriz="&Ubound($mListado) & @crlf)
;~          ConsoleWrite("---------------------------------------------" & @crlf)
         _cw("Página de descarga: " &$mListado[$Contador][0])
         $WebEnlaceDescarga=_INetGetSourceEx($mListado[$Contador][0])   ; Carga la página de descarga
         $CapEnlaceServidor=StringRegExp($WebEnlaceDescarga,'<tr class="down"><td><a href="(.*?)" target="_blank">Descargar ahora</a>',3)
         _cw($CapEnlaceServidor[0] &@CRLF)
         FileWriteLine($file, $mListado[$Contador][2] & @TAB & $mListado[$Contador][3] & @TAB & $mListado[$Contador][1] & @TAB & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & @TAB & $mListado[$Contador][4] & @TAB & $mListado[$Contador][5] & @TAB & $mListado[$Contador][6] & @TAB & $mListado[$Contador][7] & @TAB & $mListado[$Contador][8] & @TAB & $mListado[$Contador][9] & @CRLF)
         ;FileWriteLine($file, $mListado[$Contador][2] & "|" & $mListado[$Contador][3] & "|" & $mListado[$Contador][1] & "|" & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & "|" & $mListado[$Contador][4] & "|" & $mListado[$Contador][5] & "|" & $mListado[$Contador][6] & "|" & $mListado[$Contador][7] & "|" & $mListado[$Contador][8] & "|" & $mListado[$Contador][9] & @CRLF)
         _GUICtrlEdit_AppendText($edResultados,$mListado[$Contador][2] & @TAB & $mListado[$Contador][3] & @TAB & $mListado[$Contador][1] & @TAB & "http://www.seriesyonkis.com" & $CapEnlaceServidor[0] & @TAB & $mListado[$Contador][4] & @TAB & $mListado[$Contador][5] & @TAB & $mListado[$Contador][6] & @TAB & $mListado[$Contador][7] & @TAB & $mListado[$Contador][8] & @TAB & $mListado[$Contador][9] & @CRLF)

         $Contador=$Contador+1
         EndIf
      Next

;~       _ArrayDisplay($mListado,"Descargas")   ; Muestra la matriz de resultados


   Next

   FileClose($file)   ; Cierra el archivo de texto donde se guardan los resultados

   msgbox(0,"Descarga Finalizada","Se ha creado el archivo " & $NombreArchivo & " con los capítulos y sus enlaces a descarga del servidor.")
   ShellExecute($NombreArchivo, "", @ScriptDir, "edit")

EndFunc ; CapturarEnlaces()



Func _INetGetSourceEx($s_URL, $bString = True)
   ; Foro AutoitScrip.com: http://www.autoitscript.com/forum/topic/107500-inetgetsource-utf-8-problem/page__view__findpost__p__758141
    Local $sString = InetRead($s_URL, 1)
    Local $nError = @error, $nExtended = @extended
    If $bString Then $sString = BinaryToString($sString,4)
    Return SetError($nError, $nExtended, $sString)
EndFunc   ;==>_INetGetSourceEx

; Funciones _m y _cw para mostrar MsgBox y ConsoleWrite (en función del valor de $depuracíon)
   Func _m($msj="",$a=@ScriptLineNumber)
      If $depuracion=1 then msgbox(0,"Linea " & $a,$msj)
   EndFunc

   Func _cw($msj="",$a=@ScriptLineNumber)
      If $depuracion=1 then ConsoleWrite("[L:"&$a & "] " & $msj & @CRLF)
   EndFunc

;chefito
Func Cancelar()
   $nMsg = GUIGetMsg()
   Switch $nMsg
		Case $GUI_EVENT_CLOSE
			AdlibUnRegister("Cancelar")
			$Cancelar=True
			FileClose($file)   ; Cierra el archivo de texto donde se guardan los resultados
			Exit
		Case $btCancelar
			AdlibUnRegister("Cancelar")
			$Cancelar=True
	EndSwitch
EndFunc
#EndRegion =========================== FUNCIONES ===========================

Como puedes observar he marcado mis modificaciones con un comentario que pone chefito.

Lo que he hecho es crear un adlib (también puede ser con un _Timer_SetTimer) que ejecuta una función de cancelación cuando pulsas el botón Capturar. Yo he creado otro botón ($btCancelar) para cancelar esta captura. Cuando pulsas el botón cancelar o cerrar ventana, la función Cancelar que se ejecuta cada 50 milisegundos, recoge los eventos, y cambian el estado de una variable auxiliar a true ($Cancelar).
Observamos que esta variable está en dos if (uno por cada bucle for) que hace que si se ejecuta lo que hay dentro de los if...then.... salga de los bucles, cerrando el archivo y terminando la función de captura.
Como puedes observar el cierre no es inmediato, pero tarda bastante poco.
Puedes acelerar el cierre metiendo más if en la función, acelerando el adlib, etc....pero ten cuidado que vaya todo bien. Y vigila donde pones las salidas de bucles, no sea que te dejes algo sin ejecutar (por ejemplo, cerrar el fichero....aunque en este caso no hace falta ya que lo cierras al final. Hace falta al salir del script).

Es algo chapucerilla, pero funciona :smt005 .
Otra forma sería parecida a esta, pero en vez de con adlib, podrías utilizar los eventos que se producen en el edit, para así no generar un contador contínuo.

Puedes probar el código de este post que puso Jonny (sacado del foro ingles):
http://www.emesn.com/autoitforum/viewto ... 222#p12222
Por lo visto es utilización de multihilo en autoit. Pero con este código ya pasamos a palabras mayores :smt005 .

Ya nos contarás.

Saludos.
Cita vista en algún lugar de la red: En este mundo hay 10 tipos de personas, los que saben binario y los que no ;).
jamaro
Hacker del Foro
Mensajes: 253
Registrado: 03 Nov 2010, 23:04

Re: Capturador de enlaces Series

Mensaje por jamaro »

Gracias Ximorro, BBasicos y Chefito por los comentarios.

1º He cambiado el modo en que se maneja el GUI utilizando ahora EVENTOS y, salvo que lo haya hecho mal, no se para el proceso mientras está descargando los datos.
2º Lo que sí funciona es HotKey (ahora tengo que ver cómo hacer que salga del programa si está "en reposo" o que lo deje "en reposos" si está dentro de la función de captura de datos.
3º Si no consigo resultados positivos probaré la opción de Chefito.

Basicos tus ideas están muy bien, aunque de momento sólo era un programa "piloto" para unos amigos. Si veo que les resulta práctico quizás haga cambios y añada cosas de las que dices. Sino, de momento se queda así, sencillito :-)

Un saludo.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturador de enlaces Series

Mensaje por Ximorro »

¿No salta con OnEvent? ¡Qué raro! Si estás ejecutando código AutoIt lo normal es que el disparo del evento no falle, igual que las interrupciones Adlib.
Hombre, conociendo como trabajas no creo que lo hayas hecho mal, los eventos funcionan mientras no estás descargando ¿no? Entonces no es ese el problema. No uses a la vez el modo OnEvent y la función GuiGetMsg ¿eh? sólo funciona una.

¿Cómo estás descargando, InetGet? ¿algo que en realidad está bloqueando TODO el código AutoIT, no sólo los eventos? (como llamadas a dll externas del sistema)
Ah, perdón, si no me equivoco lo haces todo con esa función _INetGetSourceEx que realmente usa InetRead.
Quizás el problema esté en esta función, puede que mientras se está ejecutando el código AutoIt queda paralizado (recuerda que no es multitherading) y no esté respondiendo a los eventos.
Puede que el hotkey funcione por ser un gancho que se coloca en el sistema operativo, externo al proceso.
En fin, pues prueba lo de Chefito y mira quédate con lo que te resulte más cómodo.

También podrías probar a usar InetGet en vez de InetRead. A diferencia del segundo, InetGet tiene una opción para descargar en segundo plano (¿quién digo que AutoIT no es multithreading? :smt005 )
Después del InetGet sería cosa de poner un bucle donde usando InetGetInfo ves si ha terminado la descarga. Ese bucle seguro que los eventos OnEvent lo pueden interrumpir, a diferencia de una ejecución atómica de InetRead.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Responder