V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Reimu
V2EX  ›  Python

使用 urllib2 模拟登陆 pixiv 遇到了问题

  •  
  •   Reimu · 2017-07-31 13:00:19 +08:00 · 3184 次点击
    这是一个创建于 2705 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用的是 Python2+urllib2+cookielib 模拟登陆 pixiv,post 表单后尝试获取个人收藏页面但是得到的是 pixiv 的登录页面,怀疑是模拟登陆的过程有问题,排查了一天也没解决,实在不知道哪里错了。。求各位大手看一下,谢谢。。(账号和密码我给抹去了)

    import re,urllib,urllib2
    import cookielib
    
    headers = {
                'Referer': 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index',
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) '
                              'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
            }
    request_loginpage = urllib2.Request(r'https://accounts.pixiv.net/login')
    getLoginPage = urllib2.urlopen(request_loginpage)
    pattern = re.compile(r'<input type="hidden" name="post_key" value="(.*?)">')
    getPostKey = re.search(pattern,getLoginPage.read())
    postKey = getPostKey.group(1)
    print postKey
    data = {
        'pixiv_id':'id',
        'password':'password',
        'post_key':postKey,
        'return_to':'https://www.pixiv.net/'
    }
    
    cookie = cookielib.CookieJar()
    handler=urllib2.HTTPCookieProcessor(cookie)
    opener = urllib2.build_opener(handler)
    
    encodeData = urllib.urlencode(data)
    request = urllib2.Request('https://accounts.pixiv.net/api/login?lang=zh',encodeData,headers)
    
    response = opener.open(request)
    
    request2 = urllib2.Request('https://www.pixiv.net/bookmark.php')
    response2 = opener.open(request2)
    print response2.read()
    
    6 条回复    2017-08-01 17:32:08 +08:00
    ivechan
        1
    ivechan  
       2017-07-31 13:16:28 +08:00
    你没有验证登录是否成功吗? 看一下 response 或许你没有登录成功呢.
    Reimu
        2
    Reimu  
    OP
       2017-07-31 13:19:20 +08:00
    @ivechan 确实是没登录成功,但是不知道哪里出了问题,提交的表单和 header 设置的应该都是没错的,我用 requests 库进行模拟登陆都成功了,所以特别疑惑
    ivechan
        3
    ivechan  
       2017-07-31 14:46:00 +08:00
    @Reimu 你可以用 fiddler (Windows) 或者其他监控程序来看看你 urllib2 和 requests 发送的 HTTP 请求内容具体有什么不同.
    qwjhb
        4
    qwjhb  
       2017-07-31 15:37:27 +08:00
    github 上看来下 好像都是用 oauth 的

    def auth(self, username=None, password=None, refresh_token=None):
    """Login with password, or use the refresh_token to acquire a new bearer token"""

    url = 'https://oauth.secure.pixiv.net/auth/token'
    headers = {
    'App-OS': 'ios',
    'App-OS-Version': '10.3.1',
    'App-Version': '6.7.1',
    'User-Agent': 'PixivIOSApp/6.7.1 (iOS 10.3.1; iPhone8,1)',
    }
    data = {
    'get_secure_url': 1,
    'client_id': 'bYGKuGVw91e0NMfPGp44euvGt59s',
    'client_secret': 'HP3RmkgAmEGro0gn1x9ioawQE8WMfvLXDz3ZqxpK',
    }

    if (username is not None) and (password is not None):
    data['grant_type'] = 'password'
    data['username'] = username
    data['password'] = password
    elif (refresh_token is not None) or (self.refresh_token is not None):
    data['grant_type'] = 'refresh_token'
    data['refresh_token'] = refresh_token or self.refresh_token
    else:
    raise PixivError('[ERROR] auth() but no password or refresh_token is set.')

    r = self.requests_call('POST', url, headers=headers, data=data)
    if (r.status_code not in [200, 301, 302]):
    if data['grant_type'] == 'password':
    raise PixivError('[ERROR] auth() failed! check username and password.\nHTTP %s: %s' % (r.status_code, r.text), header=r.headers, body=r.text)
    else:
    raise PixivError('[ERROR] auth() failed! check refresh_token.\nHTTP %s: %s' % (r.status_code, r.text), header=r.headers, body=r.text)

    token = None
    try:
    # get access_token
    token = self.parse_json(r.text)
    self.access_token = token.response.access_token
    self.user_id = token.response.user.id
    self.refresh_token = token.response.refresh_token
    except:
    raise PixivError('Get access_token error! Response: %s' % (token), header=r.headers, body=r.text)

    # return auth/token response
    return token
    Reimu
        5
    Reimu  
    OP
       2017-07-31 19:14:46 +08:00
    @ivechan 非常感谢你的方法,用工具抓包发现是因为 p 站在打开登陆界面会设置一个 cookie,用 requests 库发包的时候会自动把那个 cookie 带上,而 urllib2 得自己设置
    timwei
        6
    timwei  
       2017-08-01 17:32:08 +08:00
    @Reimu

    Pixiv 在用户首次访问时,会设置一个 post_key 做为 CSRF 防护

    并不用读取 cookies,这个 post_key 会放在响应的 body 中

    你可以用 /postKey\":\"([a-zA-Z0-9]+)\"/ 匹配得到
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4096 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:23 · PVG 13:23 · LAX 21:23 · JFK 00:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.