2011-01-18 27 views
13

Deseo enviar el inicio de sesión al sitio web Reddit.com, navegar a un área particular de la página y enviar un comentario. No veo cuál es el problema con este código, pero no está funcionando porque no se refleja ningún cambio en el sitio de Reddit.Uso de Python y Mechanize para enviar datos del formulario y autenticar

import mechanize 
import cookielib 


def main(): 

#Browser 
br = mechanize.Browser() 


# Cookie Jar 
cj = cookielib.LWPCookieJar() 
br.set_cookiejar(cj) 

# Browser options 
br.set_handle_equiv(True) 
br.set_handle_gzip(True) 
br.set_handle_redirect(True) 
br.set_handle_referer(True) 
br.set_handle_robots(False) 

# Follows refresh 0 but not hangs on refresh > 0 
br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) 

#Opens the site to be navigated 
r= br.open('http://www.reddit.com') 
html = r.read() 

# Select the second (index one) form 
br.select_form(nr=1) 

# User credentials 
br.form['user'] = 'DUMMYUSERNAME' 
br.form['passwd'] = 'DUMMYPASSWORD' 

# Login 
br.submit() 

#Open up comment page 
r= br.open('http://www.reddit.com/r/PoopSandwiches/comments/f47f8/testing/') 
html = r.read() 

#Text box is the 8th form on the page (which, I believe, is the text area) 
br.select_form(nr=7) 

#Change 'text' value to a testing string 
br.form['text']= "this is an automated test" 

#Submit the information 
br.submit() 

¿Qué pasa con esto?

+0

Intenta agregar un descanso de al menos 10 segundos. También debe inspeccionar (no 'Ver código fuente', sino 'Inspeccionar elemento' en Chrome o similar en FF) el formulario en su navegador y compararlo con el HTML descargado. Podría tener campos llenados dinámicamente por JS. – TryPyPy

+1

Por cierto, Reddit tiene una API, ¿no funcionaría mejor? – TryPyPy

+0

Hmm, déjame intentar agregar sueño. No estoy seguro de cómo usar API ya que no hay documentación para enviar comentarios. – Parseltongue

Respuesta

18

Definitivamente sugeriría probar a utilizar la API si es posible, pero esto funciona para mí (no por su ejemplo de ciudad, que ha sido eliminado, pero para cualquier activo):

#!/usr/bin/env python 

import mechanize 
import cookielib 
import urllib 
import logging 
import sys 

def main(): 

    br = mechanize.Browser() 
    cj = cookielib.LWPCookieJar() 
    br.set_cookiejar(cj) 

    br.set_handle_equiv(True) 
    br.set_handle_gzip(True) 
    br.set_handle_redirect(True) 
    br.set_handle_referer(True) 
    br.set_handle_robots(False) 

    br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) 

    r= br.open('http://www.reddit.com') 

    # Select the second (index one) form 
    br.select_form(nr=1) 

    # User credentials 
    br.form['user'] = 'user' 
    br.form['passwd'] = 'passwd' 

    # Login 
    br.submit() 

    # Open up comment page 
    posting = 'http://www.reddit.com/r/PoopSandwiches/comments/f47f8/testing/' 
    rval = 'PoopSandwiches' 
    # you can get the rval in other ways, but this will work for testing 

    r = br.open(posting) 

    # You need the 'uh' value from the first form 
    br.select_form(nr=0) 
    uh = br.form['uh'] 

    br.select_form(nr=7) 
    thing_id = br.form['thing_id'] 
    id = '#' + br.form.attrs['id'] 
    # The id that gets posted is the form id with a '#' prepended. 

    data = {'uh':uh, 'thing_id':thing_id, 'id':id, 'renderstyle':'html', 'r':rval, 'text':"Your text here!"} 
    new_data_dict = dict((k, urllib.quote(v).replace('%20', '+')) for k, v in data.iteritems()) 

    # not sure if the replace needs to happen, I did it anyway 
    new_data = 'thing_id=%(thing_id)s&text=%(text)s&id=%(id)s&r=%(r)s&uh=%(uh)s&renderstyle=%(renderstyle)s' %(new_data_dict) 

    # not sure which of these headers are really needed, but it works with all 
    # of them, so why not just include them. 
    req = mechanize.Request('http://www.reddit.com/api/comment', new_data) 
    req.add_header('Referer', posting) 
    req.add_header('Accept', ' application/json, text/javascript, */*') 
    req.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8') 
    req.add_header('X-Requested-With', 'XMLHttpRequest') 
    cj.add_cookie_header(req) 
    res = mechanize.urlopen(req) 

main() 

sería interesante desactivar Javascript y ver cómo se manejan los comentarios de reddit. En este momento hay un montón de magic que ocurre en una función de envío de llamada llamada al hacer su publicación. Aquí es donde se agregan los valores uh y id.

+0

Wow. Muchas gracias. Nunca me hubiera dado cuenta de eso. – Parseltongue

+0

Hmm ... Recibo este error en todos los hilos activos: ControlNotFoundError: no control matching name 'thing_id.' ¿Algunas ideas? – Parseltongue

+0

Haha, no. Usted malinterpretó esa oración, no importa en qué hilo activo use este programa, aún desencadena el error. El programa que estoy tratando de hacer es para mis propios fines. Publica capítulos de libros relevantes en un subreddit privado que modero. – Parseltongue

Cuestiones relacionadas