t6am3 发表于 2019-3-8 22:47:20

关于爬虫cookie的疑惑

楼主最近在爬自己学校的教务,发现使用浏览器的时候获得的cookie爬虫用的时候可以获取成绩也的response
而使用requests.Session获得的登陆时响应返回的cookie就无法获取成绩页的response

我自己的思路是,学校教务的cookie可能计算方式非常复杂,使用浏览器登陆时的cookie才是真的,使用爬虫的时候获得cookie便无效。。

我自己尝试了从登陆界面,再到里面获取成绩页的页面,一直在看请求头的cookie,都一直一样,也不是没点一下cookie就稍变了这种,应该是一开始建立Session的时候就已经确定了
所以问题只可能是在最一开始建立的时候,就给了我的爬虫一个假cookie,请问有大佬知道是怎么实现这样的做法吗

吐槽一下破教务居然还有这种。。。{:9_220:}

Stubborn 发表于 2019-3-8 22:56:16

本帖最后由 Stubborn 于 2019-3-8 23:11 编辑

爬虫就是模拟用户浏览的行为,不存在给你一个假的cookie,你确认下,需不需要额外的请求,来获得需要的额外cookie.
下面是我爬12306网页的网络请求代码:其中,在115行author函数就额外获取了2个cookie,
from PyQt5.Qt import *
from urllib.parse import unquote,quote
import requests,json,base64,re,os,time

class Config(object):

    map_dic = {"1": "hard_seat","9":"business_seat","6":"vip_soft_bed","4":"soft_bed","3":"hard_bed","0":"second_seat","M":"first_seat","F":"move_bed","WZ":"no_seat"}

    @staticmethod
    def get_station_file_path():
      currrent_path = os.path.realpath(__file__) #文件绝对路径
      #print(currrent_path)
      current_dir = os.path.split(currrent_path)
      return current_dir + r"\staionse.json"

    @staticmethod
    def get_yzm_file_path():
      currrent_path = os.path.realpath(__file__) #文件绝对路径
      #print(currrent_path)
      current_dir = os.path.split(currrent_path)
      return current_dir + r"\yzm.jpg"

class TimeToll(object):
    @staticmethod
    def getTrainFormatDate(train_data):
      date_arr = time.strptime(train_data,"%Y%m%d")
      time_tamp = time.mktime(date_arr)
      time_local = time.localtime(time_tamp)
      format = "%a %b %d %Y %H:%M:%S GMT+0800 (China Standard Time)"
      return time.strftime(format,time_local)

class API(object):
    #下载验证码GET
    GET_YZM_URL = "https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand"

    #校验验证码 POST
    # callback: jQuery191037043257607249735_1550240582305
    # answer: 188, 112, 128, 116
    # rand: sjrand
    # login_site: E
    # _: 1550240582307
    CHECK_YZM_URL = "https://kyfw.12306.cn/passport/captcha/captcha-check?callback"

    #登陆验证 POST
    #username : **
    #password:**
    #appid:otn
    #answer: 253,20,29,29
    CHECK_ACCOUNT_PWD_URL = "https://kyfw.12306.cn/passport/web/login"

    #uamtk POST请求,获取第一个cookie值
    UAMTK_URL = "https://kyfw.12306.cn/passport/web/auth/uamtk"

    #authorclient POST
    #appid:otn
    #tk: 通uamtk获取
    AUTHORT_URL = "https://kyfw.12306.cn/otn/uamauthclient"
    #获取用户姓名,给予问候 POST
    HELLO_URL = "https://kyfw.12306.cn/otn/index/initMy12306Api"

   
class APITool(QObject):

    #保持会话,建立会话对象“客户端”,
    session = requests.session()

    @classmethod#类方法,因为需要共用cookies,借此保持会话
    def download_yzm(cls):
      print("API_Tool.download_yzm启动:下载验证码")
      response = cls.session.get(API.GET_YZM_URL)
      yzm_file_path = Config.get_yzm_file_path()
      _base64 = (response.json()["image"])
      content = base64.b64decode(_base64)
      with open(yzm_file_path,"wb") as f:
            f.write(content)
      print("API_Tool.download_yzm退出:返回验证码路径")
      return yzm_file_path

    @classmethod
    def check_yzm(cls,yzm):
      print("API_Tool.check_yzm启动:校验验证码")
      data_dic = {
            #"callback": "jQuery191037043257607249735_1550240582305",
            "answer": yzm,
            "rand": "sjrand",
            "login_site": "E",
            #"_": "1550240582307"
      }
      response = cls.session.post(API.CHECK_YZM_URL,data=data_dic)
      result = re.findall(r'.*"(.*)"\}.*',response.text)
      print("API_Tool.check_yzm退出:校验结果=",response.text)
      return result == "4"


    @classmethod
    def check_account_pwd(cls,account,pwd,answer):
      print("API_Tool.check_account_pwd启动:验证登录")
      data_dict = {
            "username" : account,
            "password":pwd,
            "appid":"otn",
            "answer": answer
      }
      response = cls.session.post(API.CHECK_ACCOUNT_PWD_URL,data=data_dict)
      result_code = response.json()["result_code"]
      if result_code == 0:
            cls.author() #授权
            print("API_Tool.check_account_pwd退出:验证通过")
            return ",".join(cls.get_hellow())
      else:
            print("API_Tool.check_account_pwd退出:验证失败")
            return None #授权失败

    @classmethod
    def author(cls):
      print("API_Tool.author启动:获取tk值")
      response = cls.session.post(API.UAMTK_URL,data={"appid":"otn"})
      tk = response.json()["newapptk"]
      print("UAMTK获取成功=",tk)
      cls.session.post(API.AUTHORT_URL,data={"tk":tk})
      print("第二个cookie获取成功")


    @classmethod
    def get_hellow(cls):
      "注意比对cookie值"
      print("API_Tool.get_hellow启动:获取问候信息")
      response = cls.session.post(API.HELLO_URL)
      dic = response.json()
      if dic["httpstatus"] == 200:#获取信息成功
            print("API_Tool.get_hellow退出:",dic["data"]["user_name"],dic["data"]["user_regard"])
            return (dic["data"]["user_name"],dic["data"]["user_regard"]) #用户名 +问候
      else:
            print("API_Tool.get_hellow退出:获取问候信息失败")
            return ("","")





t6am3 发表于 2019-3-8 23:01:46

Stubborn 发表于 2019-3-8 22:56
爬虫就是模拟用户浏览的行为,不存在给你一个假的cookie,你确认下,需不需要额外的请求,来获得需要的额外 ...

你好,我确认过了从浏览器访问时获得的cookie与爬虫Session获得的cookie等长,形式一样。
且我使用浏览器获得的cookie粘贴到爬虫里,也可以获得response,但是使用爬虫会话的cookie就获得空

Stubborn 发表于 2019-3-8 23:05:51

t6am3 发表于 2019-3-8 23:01
你好,我确认过了从浏览器访问时获得的cookie与爬虫Session获得的cookie等长,形式一样。
且我使用浏览 ...

只能内网爬么{:10_254:} 不然我去看看{:10_245:}

t6am3 发表于 2019-3-8 23:19:29

本帖最后由 t6am3 于 2019-3-8 23:21 编辑

Stubborn 发表于 2019-3-8 23:05
只能内网爬么 不然我去看看

对的{:10_285:}
我详细比对了两条不同的cookie,从爬虫session获得的cookieB039A199A936D99789E8E5379B877945.tomcat77_1
与从Browser获得的
D82FCE15DF573FBEE86A4A7C2FD470CA.tomcat77_1
实际上cookie还有其他的字符串,但是除了这一段之外都一样,证据就是使用浏览器获得的cookie在爬虫headers里面粘贴也可以获得response, 但是使用爬虫获得的就不可以。。。

很难受,输出
03CFBF101DCB5D6B619260C17283AC01.tomcat77_1
6532
长度相等吗? True
D82FCE15DF573FBEE86A4A7C2FD470CA.tomcat77_1
{'Server': 'nginx/1.15.3.1 Crow', 'Date': 'Fri, 08 Mar 2019 15:17:26 GMT', 'Content-Type': 'text/html;charset=GBK', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive'}
中间6532是验证码,最后一个字典是res头,是用浏览器的cookie登陆时返回的,否则就返回
7DD897DBF17F161DFB3FBABF5C104FB2.tomcat77_1
1296
长度相等吗? True
D82FCE15DF573FBEE86A4A7C2FD470CA.tomcat77_1
{'Server': 'nginx/1.15.3.1 Crow', 'Date': 'Fri, 08 Mar 2019 15:20:53 GMT', 'Content-Type': 'text/html;charset=GBK', 'Content-Length': '0', 'Connection': 'keep-alive'}

Stubborn 发表于 2019-3-8 23:28:09

t6am3 发表于 2019-3-8 23:19
对的
我详细比对了两条不同的cookie,从爬虫session获得的cookie
与从Browser获得的


代码不长贴上来,研究研究{:10_258:} 还有获取cookie的url 截图

t6am3 发表于 2019-3-8 23:30:05

Stubborn 发表于 2019-3-8 23:05
只能内网爬么 不然我去看看

因为我用浏览器时, cookie一直也没有变过,从我登陆时到获取成绩页
所以想来也不需要多次获取cookie多个字段?

t6am3 发表于 2019-3-8 23:33:49

本帖最后由 t6am3 于 2019-3-8 23:48 编辑

Stubborn 发表于 2019-3-8 23:05
只能内网爬么 不然我去看看

贴一点代码。。我是新手,,但是实在没想通咋回事
import requests
import datetime
import os
from vertificationCodeReg import vertificationCode
from PIL import Image
from PIL import ImageEnhance
from bs4 importBeautifulSoup as bs

s = requests.Session()

def login():
    initialUrl = ##不显示##
    initHeaders = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Connection': 'keep-alive', 'Host': 'gsmis.graduate.buaa.edu.cn', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}
    s.get(initialUrl, headers=initHeaders)

    headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
               'Accept-Encoding': 'gzip, deflate',
               'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
               'Cache-Control': 'max-age=0',
               'Connection': 'keep-alive',
               'Content-Length': '45',
               'Content-Type': 'application/x-www-form-urlencoded',
               'Host': ##不显示##
               'Origin': ##不显示##
               'Referer': ##不显示##
               'Upgrade-Insecure-Requests': '1',
               'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
               }

    JSESSIONID = s.cookies.get_dict()['JSESSIONID']
    headers[ 'Cookie'] = f'JSESSIONID={JSESSIONID}; _ga=GA1.3.1234387313.1538569273; Hm_lvt_8edeba7d3ae859d72148a873531e0fa5=1539923770,1542172342; UM_distinctid=16771ed7aac159-028525f4a66be6-3a3a5d0c-1fa400-16771ed7aad774; CASTGC=TGT-189864-kqSVcobA7GQmbUEG0qmKaEGETmevCpUZL7Tv6VRWOi5HHRY61w-cas'

    loginUrl = ##不显示##

    data = {
       #此部分为隐私
    }
    s.post(loginUrl, headers=headers, data=data)

def gradeQuery():
    headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
               'Accept-Encoding': 'gzip, deflate',
               'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
               'Connection': 'keep-alive',
               'Host': '##不显示##
               'Referer':##不显示##
               'Upgrade-Insecure-Requests': '1',
               'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}
    url = ##不显示##
    #print('query', s.cookies.get_dict())
   
    # 使用这个获取不到response
    JSESSIONID1 = s.cookies.get_dict()['JSESSIONID']
    print("这是Session的cookie", JSESSIONID1)
    # 使用这个获取的到response
    JSESSIONID2 = 'D82FCE15DF573FBEE86A4A7C2FD470CA.tomcat77_1'
    print("这是浏览器的cookie", JSESSIONID2)
    print("长度相等吗?", len(JSESSIONID1)==len(JSESSIONID2))
    headers['Cookie'] = f'JSESSIONID={JSESSIONID1}; _ga=GA1.3.1234387313.1538569273; Hm_lvt_8edeba7d3ae859d72148a873531e0fa5=1539923770,1542172342; UM_distinctid=16771ed7aac159-028525f4a66be6-3a3a5d0c-1fa400-16771ed7aad774; CASTGC=TGT-189864-kqSVcobA7GQmbUEG0qmKaEGETmevCpUZL7Tv6VRWOi5HHRY61w-cas'

    response = requests.get(url, headers=headers)
    print(response.headers)
    soup = bs(response.text, features="lxml")
    with open('response1.html', 'w') as f:
      f.write(response.text)
    #print(soup)
    #parseSoup(soup)

t6am3 发表于 2019-3-8 23:36:51

_谪仙 发表于 2019-3-8 23:35
教务系统有Cookies登录和无Cookies的

这个需要cookies,并且我使用浏览器中截取的cookies粘贴进headers,可以get到response

_谪仙 发表于 2019-3-8 23:40:51

我想问下,你既然使用Session了,还要cookies干嘛?

t6am3 发表于 2019-3-8 23:43:17

本帖最后由 t6am3 于 2019-3-8 23:45 编辑

_谪仙 发表于 2019-3-8 23:40
我想问下,你既然使用Session了,还要cookies干嘛?

因为Session获得的cookies和提交表单的cookies不一样,
Session.cookies.get_dict()获得的字典里只有cookies的一部分字段
但是也只有这一部分字段的cookies是变化的,其他部分的cookies没有变化,所以我获取了这一部分,套进要提交的cookies里就可以提交,
比如我从浏览器里也复制cookies的这变化的一小段,放进我的cookie字段里,就可以get到response,我的代码里就是这么写的,
54-61行

_谪仙 发表于 2019-3-8 23:48:00

使用了session可以不需要cookies,session就是帮你维持本地会话,

t6am3 发表于 2019-3-8 23:49:11

_谪仙 发表于 2019-3-8 23:48
使用了session可以不需要cookies,session就是帮你维持本地会话,

就是维持不了我才没有只使用session的
因为session里的cookies不完全。。。我把里面的字段复制进表单的一部分才可以使用

Stubborn 发表于 2019-3-8 23:54:01

本帖最后由 Stubborn 于 2019-3-8 23:59 编辑

t6am3 发表于 2019-3-8 23:49
就是维持不了我才没有只使用session的
因为session里的cookies不完全。。。我把里面的字段复制进表单的 ...

{:10_299:}cookies不全,通过额外的网络请求,服务器肯定会给您cookie,不会凭空生出来,我用session去怕12306,从登录到订票,都是用session维持,校内网总不会比12306难爬吧{:10_284:}
我上面的代码51行:

#uamtk POST请求,获取第一个cookie值
    UAMTK_URL = "https://kyfw.12306.cn/passport/web/auth/uamtk"

    #authorclient POST
    #appid:otn
    #tk: 通uamtk获取
    AUTHORT_URL = "https://kyfw.12306.cn/otn/uamauthclient"
    #获取用户姓名,给予问候 POST
    HELLO_URL = "https://kyfw.12306.cn/otn/index/initMy12306Api"
以及114行 通过UAMTK_URL这个网址获取第一个tk的cookie值,然后用tk的cookie值,进行AUTHORT_URL这个网址,继续获取第二个cookie,两个cookie获取完了,才能获取到正确的已经登录的界面
    @classmethod
    def author(cls):
      print("API_Tool.author启动:获取tk值")
      response = cls.session.post(API.UAMTK_URL,data={"appid":"otn"})
      tk = response.json()["newapptk"]
      print("UAMTK获取成功=",tk)
      cls.session.post(API.AUTHORT_URL,data={"tk":tk})
      print("第二个cookie获取成功")

就是用来获取额外的cookie值

t6am3 发表于 2019-3-9 00:01:47

Stubborn 发表于 2019-3-8 23:54
cookies不全,通过额外的网络请求,服务器肯定会给您cookie,不会凭空生出来,我用session去 ...

我觉得你说的很有道理,但是我就是很奇怪,为啥我用浏览器复制过来的cookie,凑进去也可以返回想要的界面。。就这种
headers['Cookie'] = f'JSESSIONID={JSESSIONID1}; _ga=GA1.3.1234387313.1538569273; Hm_lvt_8edeba7d3ae859d72148a873531e0fa5=1539923770,1542172342; UM_distinctid=16771ed7aac159-028525f4a66be6-3a3a5d0c-1fa400-16771ed7aad774; CASTGC=TGT-189864-kqSVcobA7GQmbUEG0qmKaEGETmevCpUZL7Tv6VRWOi5HHRY61w-cas'
因为多次比对,发现后面一串实在是固定值

Stubborn 发表于 2019-3-9 00:06:29

t6am3 发表于 2019-3-9 00:01
我觉得你说的很有道理,但是我就是很奇怪,为啥我用浏览器复制过来的cookie,凑进去也可以返回想要的界面 ...

试试,直接请求,看看返回了什么cookie值,在和浏览器对比,下有没有少

t6am3 发表于 2019-3-9 00:09:34

本帖最后由 t6am3 于 2019-3-9 00:10 编辑

Stubborn 发表于 2019-3-8 23:54
cookies不全,通过额外的网络请求,服务器肯定会给您cookie,不会凭空生出来,我用session去 ...

我知道肯定是我的问题。。。我再研究一下,另外我想问一下 抓的包的response头里面没有set-cookies,是不是这个原因,还是因为我chrome的设置不显示set-cookies?还是因为我没有找到有set-cookies的包。。。
我找cookie字段是从request头里面找的,因为response里面一直没有看到有cookies字段
萌新的问题很幼稚。。

Stubborn 发表于 2019-3-9 00:23:38

t6am3 发表于 2019-3-9 00:09
我知道肯定是我的问题。。。我再研究一下,另外我想问一下 抓的包的response头里面没有set-cookies,是 ...

抓包浏览器开无痕模式去抓包,是开无痕的吗?不然谷歌会缓存的

wongyusing 发表于 2019-3-9 00:25:08

你打印一下状态码,看一下是多少??

t6am3 发表于 2019-3-9 00:34:16

Stubborn 发表于 2019-3-9 00:23
抓包浏览器开无痕模式去抓包,是开无痕的吗?不然谷歌会缓存的

见鬼了
我。。。我找到response的cookie字段了!!!
我使用无痕模式去抓包,发现从访问登陆界面到登陆完之后在里面反复横跳,所有的response的cookies字段都为空。。。
我想找下鱼c编辑器的截图功能也找不到。。
页: [1] 2
查看完整版本: 关于爬虫cookie的疑惑