2011-01-18 13 views
13

Chcę złożyć login na stronie Reddit.com, przejść do określonego obszaru strony i wysłać komentarz. Nie widzę, co jest nie tak z tym kodem, ale nie działa, że ​​żadna zmiana nie jest odzwierciedlona na stronie Reddit.Używanie Python i Mechanize do przesyłania danych formularzy i uwierzytelniania

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() 

Co jest nie tak z tym?

+0

Spróbuj dodać sen trwający co najmniej 10 sekund. Powinieneś również sprawdzić (nie "View Source", ale "Inspect Element" w Chrome lub podobnym w FF) formularz w przeglądarce i porównać z pobranym HTML. Może mieć pola dynamicznie wypełniane przez JS. – TryPyPy

+1

Nawiasem mówiąc, Reddit ma API, czy to nie działa lepiej? – TryPyPy

+0

Hmm, pozwól mi spróbować dodać sen. Nie wiem, jak korzystać z interfejsu API, ponieważ nie ma dokumentacji do przesyłania komentarzy. – Parseltongue

Odpowiedz

18

zdecydowanie sugerujemy próbuje użyć API, jeśli to możliwe, ale to działa na mnie (nie za przykładowy post, który został usunięty, ale za każdym aktywnym):

#!/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() 

Byłoby ciekawe, aby wyłączyć javascript i zobaczyć, jak wtedy obsługiwane są komentarze reddit. W tej chwili jest pęczek magic, który występuje w funkcji onsubmit wywoływanej podczas tworzenia postu. Tutaj dodawane są wartości uh i id.

+0

Wow. Dziękuję bardzo. Nigdy bym tego nie rozgryzł. – Parseltongue

+0

Hmm ... Otrzymuję ten błąd we wszystkich aktywnych wątkach: ControlNotFoundError: brak kontrolnego pasującego imienia "id_urządzenia". Jakieś pomysły? – Parseltongue

+0

Haha, nie. Źle zinterpretowałeś to zdanie - bez względu na to, który aktywny wątek korzystam z tego programu, nadal wyzwala błąd. Program, który próbuję wykonać, jest dla moich własnych celów. Publikuje stosowne rozdziały w książkach do prywatnego subredditu, który moderuję. – Parseltongue

Powiązane problemy