User Controls

Py fags, I need help...

  1. #1
    So am trying to vote on a poll, but it doesn't seem to be regisring the vote, I think I need to ad a payload or some shit, here's my example



    status_id = '835306569516507138'
    url = 'https://twitter.com/StarsPoll/status/'+status_id
    code = bs(session.get(url).text, 'html.parser')

    auth_token = code.find("input", {"name": "authenticity_token"}).attrs['value']
    #card_name = code.find("div", {"data-card2-type"}).value
    card_name = 'poll2choice_text_only'

    data = {
    'tweet_id': status_id,
    'card_name': card_name,
    'authenticity_token': auth_token,
    'forward': 'true',
    'capi_uri': 'capi%3A%2F%2Fpassthrough%2F1'

    }

    payload = {

    }


    #this is payload request when on network tab in chrome when voting?

    #"twitter:string:card_uri":"card://835331856526684160","twitter:long:original_tweet_id":"835331860725186560","twitter:string:selected_choice":"2"

    headers = {
    "Host": "www.twitter.com",
    "Origin": "https://www.twitter.com",
    "X-Requested-With": "XMLHttpRequest",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5"
    }


    voteurl = 'https://twitter.com/i/cards/api/v1.json?tweet_id='+status_id+'&card_name='+card_name+'&authenticity_token='+auth_token+'&forward=true&capi_uri=capi%3A%2F%2Fpassthrough%2F1'
    vote = session.post(voteurl, data = data, headers=headers, cookies=session.cookies)



    I'm getting a 200 status code, but still no vote.
  2. #2
    did u try turning it off and back on again?
  3. #3
    Sophie Pedophile Tech Support
    I'm not familiar with the library you're using. Is the vote button JS based? Or HTML? If it's HTML you should just use the Mechanize lib imo.
  4. #4
    Lanny Bird of Courage
    Where did you get that url? I think the v1 api has been deprecated for a while and I can't find any documentation it.
  5. #5
    Lanny Bird of Courage
    Oh wait, it's just the endpoint your browser is using?

    What's the response body?
  6. #6
    Originally posted by Lanny Oh wait, it's just the endpoint your browser is using?

    What's the response body?

    the source code:


    view-source:https://twitter.com/StarsPoll/status/835306569516507138
  7. #7
    Originally posted by Sophie I'm not familiar with the library you're using. Is the vote button JS based? Or HTML? If it's HTML you should just use the Mechanize lib imo.

    neither. I'm replicating the post request.
  8. #8
    Lanny Bird of Courage
    Oh, I see the issue, although you didn't actually post your source...

    Take a look at the content-type header on the request you make through chrome vs. the one your script is producing. In the browser it's probably going to be text/plain (which is used to transmit a JSON string) while passing a dictionary to requests will probably send it as application/x-www-form-urlencoded. Not sure how smart requests is, you might be able to set the header yourself and json.dumps your data or maybe there's more ceremony involved but I'm sure it's in the docs somewhere. The important thing to note is that while the response's content-type is application/json your request is not, I'm not sure why twitter did this, it doesn't really matter as far as I can tell, but you probably will need to follow their scheme and send as text/plain that just happens to be valid JSON.

    FYI this has nothing to do with python
  9. #9
    mmQ Lisa Turtle
    What a fucking nood!
  10. #10
    Originally posted by Lanny Oh, I see the issue, although you didn't actually post your source…

    Take a look at the content-type header on the request you make through chrome vs. the one your script is producing. In the browser it's probably going to be text/plain (which is used to transmit a JSON string) while passing a dictionary to requests will probably send it as application/x-www-form-urlencoded. Not sure how smart requests is, you might be able to set the header yourself and json.dumps your data or maybe there's more ceremony involved but I'm sure it's in the docs somewhere. The important thing to note is that while the response's content-type is application/json your request is not, I'm not sure why twitter did this, it doesn't really matter as far as I can tell, but you probably will need to follow their scheme and send as text/plain that just happens to be valid JSON.

    FYI this has nothing to do with python



    GOOD

    POST /i/cards/api/v1.json?tweet_id=835553193853607936&card_name=poll2choice_text_only&authenticity_token=3fa4898d1eb9c3970d122438069080f67e2c40a0&forward=true&capi_uri=capi%3A%2F%2Fpassthrough%2F1 HTTP/1.1
    Host: twitter.com
    Connection: keep-alive
    Content-Length: 146
    Origin: https://twitter.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Content-Type: text/plain;charset=UTF-8
    Accept: */*
    Referer: https://twitter.com/i/cards/tfw/v1/835553193853607936?cardname=poll2choice_text_only&autoplay_disabled=true&forward=true&earned=true&lang=en&card_height=114&scribe_context=%7B%22client%22%3A%22web%22%2C%22page%22%3A%22search%22%2C%22section%22%3A%22news%22%2C%22component%22%3A%22tweet%22%7D
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
    Cookie: guest_id=v1%3A148348519609568388; eu_cn=1; _ga=GA1.2.17648078.1483840185; moments_moment_guide_create_moment_tooltip=true; moments_profile_moments_nav_tooltip_self=true; moments_profile_moments_nav_tooltip_other=true; d=32; mobile_metrics_token=148355421759690664; zrca=5; u=4345167ab07c53b1c1a0b0f28ca3c23fa597e826; lang=en; kdt=wBD2EQ4hAtxU5AgI2pWJhBvaYVh86CwyARordbHz; remember_checked_on=1; twid="u=797054191420276736"; auth_token=2e4444c70ae4faccc4b89b68f268d0ffca2582c6; ct0=052eee2c9ef178e33f39a1b1effb89b9; external_referer="padhuUp37zguUvQ9eLPWcgjfN2q0WSYBeFiMalFf9QUYFrDw6JjXFQ==|0"; m5=off; _mobile_sess=BAh7ByIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7ADoQX2NzcmZfdG9rZW4iJWU5OTIzMGE4NmRmYTkyMDY0ZGIxNTAzMDQ3NzAwM2Yz--3c7ec2a6fcdc8d2e2e23eb3403864c855e95d9cb; external_referer="ziZgIoZIK4nlMKUVLq9KcnBFms0d9TqBqrE/yjvSFlFJR45yIlYF+w==|0"; _twitter_sess=BAh7CiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCL3hjF1aAToMY3NyZl9p%250AZCIlNjZmZTZjNGVmYjVkODlkYzAxYzk1NzBhODIyOWY5ZDM6B2lkIiU4YjM2%250ANmE2OGNiMGMxODdhMzhlYTQ2OTVkZWJmODI4ZjoJdXNlcmwrCQCAV2qQtA8L--9c34f3e72eedf83c6f85531b076460036abb3694
    AlexaToolbar-ALX_NS_PH: AlexaToolbar/alx-4.0.1



    BAD
    POST /i/cards/api/v1.json?tweet_id=835562654030835712&card_name=poll2choice_text_only&authenticity_token=b81b369798790ff7dde3dba3d4ad1b117ec687e8&forward=true&capi_uri=capi%3A%2F%2Fpassthrough%2F1 HTTP/1.1
    Connection: keep-alive
    Accept-Encoding: gzip, deflate
    Accept: */*
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5
    Origin: https://www.twitter.com
    Host: www.twitter.com
    X-Requested-With: XMLHttpRequest
    Cookie: remember_checked_on=1; ct0=d46435d2c2d85abcb4f9fb2c8073f03b; _twitter_sess=BAh7CiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCNyzMXdaAToMY3NyZl9p%250AZCIlYzQ3ZTJlYWViYjkwZmEyOTYzYjZmOWEzN2ExMTZkZWY6B2lkIiVmYWI1%250AYmE2MGNjZjcwZWEzMjA0NjdkMDVkNDM3Y2ZjNzoJdXNlcmwrBxX5Xp8%253D--dc874a43cd229d67910c46349ab308b34c3e4aa9; auth_token=89d44c89919ebe49e61263615f731a11e8c20349; guest_id=v1%3A148805843042642246; twid="u=2673801493"; kdt=PEQqxFONd9KhIWG4hUSiToDB58U5qsxPR3ZJLNRX; lang=en
    Content-Length: 178
    Content-Type: application/x-www-form-urlencoded
  11. #11
    Don't worry, the auth tokens have expired.
  12. #12
    Lanny Bird of Courage
    wait, so did it work?
  13. #13
    Nope, even with the new one



    POST /i/cards/api/v1.json?tweet_id=835538193269215237&card_name=poll2choice_text_only&authenticity_token=8d565ef82d56a9a455389621f5b17e3f6e98aad9&forward=true&capi_uri=capi%3A%2F%2Fpassthrough%2F1 HTTP/1.1
    Connection: keep-alive
    Accept-Encoding: gzip, deflate, br
    Accept: */*
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Origin: https://twitter.com
    Host: twitter.com
    Referer: https://twitter.com/i/cards/tfw/v1/835538193269215237?cardname=poll2choice_text_only&autoplay_disabled=true&forward=true&earned=true&lang=en&card_height=114&scribe_context=%7B%22client%22%3A%22web%22%2C%22page%22%3A%22search%22%2C%22section%22%3A%22news%22%2C%22component%22%3A%22tweet%22%7D
    AlexaToolbar-ALX_NS_PH: AlexaToolbar/alx-4.0.1
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
    Content-Type: text/plain;charset=UTF-8
    Cookie: remember_checked_on=1; ct0=11f3b1310a3c890366a358e68641a5c7; _twitter_sess=BAh7CiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCDO%252BS3daAToMY3NyZl9p%250AZCIlMmVjN2QyYzhjMGY4ZmQ2OTIxYjUwM2MwNTU5MTFlZDk6B2lkIiU1ZWY0%250AZWJkMjAxYjFiN2MzYzIwMDczMTIyYmExNDg2ZjoJdXNlcmwrCQCAV2qQtA8L--d9d8542ca65d390ce4e55dc29f7f841dcbafc8fc; auth_token=2ee0094edd29f886e1b2ff111f3ccf3cc9e361d8; guest_id=v1%3A148806013701074387; twid="u=797054191420276736"; kdt=C5Q6OFdZ7EAy3RY1sJAIqpoxa12H4VxmBQzhB1dK; lang=en
    Content-Length: 178

  14. #14
    Lanny Bird of Courage
    OK, headers look reasonable, what's the request body? What are the response headers?
  15. #15

    POST https://twitter.com/i/cards/api/v1.json?tweet_id=835523028515753986&card_name=poll2choice_text_only&authenticity_token=669c3ced7948a698ccfea2205c2dc51fc4887745&forward=true&capi_uri=capi%3A%2F%2Fpassthrough%2F1 HTTP/1.1
    Connection: keep-alive
    Accept-Encoding: gzip, deflate, br
    Accept: */*
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Origin: https://twitter.com
    Host: twitter.com
    Referer: https://twitter.com/i/cards/tfw/v1/835523028515753986?cardname=poll2choice_text_only&autoplay_disabled=true&forward=true&earned=true&lang=en&card_height=114&scribe_context=%7B%22client%22%3A%22web%22%2C%22page%22%3A%22search%22%2C%22section%22%3A%22news%22%2C%22component%22%3A%22tweet%22%7D
    AlexaToolbar-ALX_NS_PH: AlexaToolbar/alx-4.0.1
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
    Content-Type: text/plain;charset=UTF-8
    Cookie: remember_checked_on=1; ct0=90c008ac2c3791405e6fbc3181d55fd9; _twitter_sess=BAh7CiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCFlTX3daAToMY3NyZl9p%250AZCIlZjM5MjE3NzRiOGYzYTExODE2Y2QxMTU0NmY4MWU3ODk6B2lkIiUzNmZm%250AN2U0NzQwN2NkOTE3YjU2YmM2ODVjYzhmNGJkZToJdXNlcmwrCQCAV2qQtA8L--6a40fd8d80ec80939990ae39fc223d3c3b7aa36a; auth_token=78a6b3c4f4119bda8f943c5a4b8f7c858355d8f8; guest_id=v1%3A148806142037727180; twid="u=797054191420276736"; kdt=5xhzgmWWJL6GjzDfnpBWTHGqR2FEqcEgQXXJ5ARY; lang=en
    Content-Length: 151

    {"twitter:long:original_tweet_id": "835523028515753986", "twitter:string:card_uri": "card://835523028515753986", "twitter:string:selected_choice": "1"}




    respone:



    HTTP/1.1 200 OK
    content-disposition: attachment; filename=json.json
    content-length: 123
    content-type: application/json;charset=utf-8
    date: Sat, 25 Feb 2017 22:24:05 GMT
    server: tsa_f
    set-cookie: fm=0; Expires=Sat, 25 Feb 2017 22:23:55 GMT; Path=/; Domain=.twitter.com; Secure; HTTPOnly
    set-cookie: _twitter_sess=BAh7CiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoPY3JlYXRlZF9hdGwrCFlTX3daAToMY3NyZl9p%250AZCIlZjM5MjE3NzRiOGYzYTExODE2Y2QxMTU0NmY4MWU3ODk6B2lkIiUzNmZm%250AN2U0NzQwN2NkOTE3YjU2YmM2ODVjYzhmNGJkZToJdXNlcmwrCQCAV2qQtA8L--6a40fd8d80ec80939990ae39fc223d3c3b7aa36a; Path=/; Domain=.twitter.com; Secure; HTTPOnly
    strict-transport-security: max-age=631138519
    x-connection-hash: cb5f9245ed42d3ba5c10c315192d81a4
    x-response-time: 133
    x-transaction: 008fc5c200506a24
    x-tsa-request-body-time: 1

    {
    "successful" : false,
    "response" : {
    "cardName" : "poll2choice_text_only",
    "message" : "Not available."
    }
    }
  16. #16
    Lanny found the problem, poll ID is different from the tweet ID :) How can I use bs to get these 2 values:


    data-card-name="poll2choice_text_only"
    data-card-url="card://835523027689435143"


    from:


    <div class="js-macaw-cards-iframe-container initial-card-height card-type-poll2choice_text_only"
    data-src="/i/cards/tfw/v1/835523028515753986?cardname=poll2choice_text_only&amp;autoplay_disabled=true&amp;earned=true&amp;lang=en"
    data-card-name="poll2choice_text_only"
    data-card-url="card://835523027689435143"
    data-publisher-id=""
    data-creator-id=""
    data-amplify-content-id=""
    data-amplify-playlist-url=""
    data-full-card-iframe-url="/i/cards/tfw/v1/835523028515753986?cardname=poll2choice_text_only&amp;autoplay_disabled=true&amp;earned=true&amp;lang=en"
    data-has-autoplayable-media="false">
    </div>


    I've tried:

    #card_name = code.find("div", {"data-card-name"})

    but that doesnt work

    Post last edited by RichardBurnish at 2017-02-25T22:38:14.388504+00:00
  17. #17
    Lanny Bird of Courage
    .find takes arbitrary kwargs, which is interpreted as search by attribute. If you pass a bool it just tests for attribute existence. The trick is that data-card-name isn't a valid identifier in python so you need to use dict destructuring to make this work like so:


    code.find("div", **{'data-card-name': True})


    Looks wierd right? A little language trivia. This:


    func(arg1, **{'some_keyword': 42})


    is always equivalent to:


    func(arg1, some_keyword=42)


    The ** syntax on the caller side says "unpack the keys of this dict-like and pass them as keywords to this function" in the same way * does list splaying. The former style can express slightly more keywords than the latter because you can express every string as a key in a dict but not as a parameter name. Kind of language wankery, I think this is the first time I've ever actually had to do this in python, but kind of a fun fact.
    The following users say it would be alright if the author of this post didn't die in a fire!
  18. #18
    Lanny Bird of Courage
    this was fun, got to bust out ncat for the first time in a while. I feel so leek
    The following users say it would be alright if the author of this post didn't die in a fire!
  19. #19
    Originally posted by Lanny .find takes arbitrary kwargs, which is interpreted as search by attribute. If you pass a bool it just tests for attribute existence. The trick is that data-card-name isn't a valid identifier in python so you need to use dict destructuring to make this work like so:


    code.find("div", **{'data-card-name': True})


    Looks wierd right? A little language trivia. This:


    func(arg1, **{'some_keyword': 42})


    is always equivalent to:


    func(arg1, some_keyword=42)


    The ** syntax on the caller side says "unpack the keys of this dict-like and pass them as keywords to this function" in the same way * does list splaying. The former style can express slightly more keywords than the latter because you can express every string as a key in a dict but not as a parameter name. Kind of language wankery, I think this is the first time I've ever actually had to do this in python, but kind of a fun fact.


    BOOM!!! thanks, bud :)

  20. #20
    Sophie Pedophile Tech Support
    Originally posted by Lanny this was fun, got to bust out ncat for the first time in a while. I feel so leek

    You are the leekest.



    Lol ancient memes.
Jump to Top