scrapy爬取知乎問題實戰

首先,須要理解cookies的含義,是存儲在瀏覽器中的內容,在本地存儲任意鍵值對,第一次訪問時服務器返回一個id存儲到本地cookie中,第二次訪問將cookies一塊兒發送到服務器中
html

常見http狀態碼python

code 說明
200 請求成功
301/302 永久重定向/臨時重定向
403 沒有權限訪問
404 沒有對應的資源
500 服務器錯誤
503 服務器停機或正在維護

要爬取知乎內容首先須要進行登陸,在本文中咱們主要介紹2種登陸方式,第一種是經過requests的session保存cookies進行登陸,第二種是經過scrapy修改start_requests函數進行登陸瀏覽器

requests進行登陸

在utils中新建zhihu_login.py,實例化一個session對象,設置其cookies對象爲cookiesjar庫中的LWPCookieJar對象,設置requests庫須要用到的headrs(從瀏覽器中進行拷貝),服務器

session = requests.session()
session.cookies = cookiejar.LWPCookieJar(filename='zhihu_cookies.txt')
headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
        'Origin':'https://www.zhihu.com',
        'Accept-Language':'zh-CN,zh;q=0.8,en;q=0.6',
        'Host':'www.zhihu.com',
        'Referer':'https://www.zhihu.com/'
}

接下來,咱們要尋找登陸發送數據的頁面,首先打開zhihu.com退出以前的登陸,來到一個登陸頁面,在登錄頁面中使用手機號碼登陸,此時須要發送一個錯誤的信息給頁面,以找到post數據的網頁(若是輸入正確的帳號密碼就直接登陸成功了,一大堆網頁請求就找不到咱們須要的網頁了)cookie

找到了須要post的網頁,發現post的數據有_xsrf,passoword,phone_num,另一個captcha_type沒有用,加了以後反而沒法訪問(不知道爲何)session

def zhihu_login(account, password):
    if re.match('1\d{10}', account):
        phone_post_url = 'https://www.zhihu.com/login/phone_num'
        post_data={
            '_xsrf':get_xsrf(),
            'phone_num':account,
            'password':password,
            # 'captcha_type':'cn'
        }
        # session_response = session.post(phone_post_url, data=post_data, headers=header)
        # print(session_response.text)
        # result_list = re.findall('"msg": "(.*?)"',session_response.text)[0]
        # print(result_list.encode('utf8').decode('unicode-escape'))
        # try:
        #     login_page = session.post(phone_post_url, data=post_data, headers=headers)
        #     print('不要驗證碼,login_code:{}'.format(login_page.status_code))
        # except:
        post_data['captcha'] = get_captcha()
        login_page = session.post(phone_post_url, data=post_data, headers=headers)
        result_list = re.findall('"msg": "(.*?)"', login_page.text)[0]
        print(result_list.encode('utf8').decode('unicode-escape'))
        session.cookies.save()
        print('保存成功')

在這裏咱們一開始沒有使用驗證碼,發現只要是爬蟲登陸都會被識別到,因此咱們編寫了一個用於生成驗證碼的代碼:app

def get_captcha():
    t = str(int(time.time()*1000))
    captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
    r = session.get(captcha_url, headers=headers)
    with open('captcha.jpg','wb') as f:
        f.write(r.content)
    try:
        im = Image.open('captcha.jpg')
        im.show()
        im.close()
    except:
        print('wrong')
    captcha = input('請輸入驗證碼:')
    return captcha

保存完cookies,咱們嘗試使用這個cookies再次登陸scrapy

def get_again():
    try:
        session.cookies.load(ignore_discard=True)
        print('cookies加載成功\n')
    except:
        print('cookies加載失敗')
    response = session.get('https://www.zhihu.com',headers=headers)
    # response.encoding = response.apparent_encoding
    with open('my_zhihu_login.html','wb') as f:
        f.write(response.text.encode('utf8'))
        print('保存頁面成功')

查看這個頁面發現不停地刷新,暫時尚未找到辦法ide

scrapy模擬登錄知乎

首先生成一個新的spider,名字爲zhihu函數

在class zhihu中定義headers等信息,重寫start_requests函數

def start_requests(self):
     return [scrapy.Request('https://www.zhihu.com/#signin',headers=self.headers, callback=self.login)]

start_requests裏面返回一個新的Request,其回調函數設置爲一個新的login函數以下:

def login(self,response):
  # print(response.text)
  # a = '<input type="hidden" name="_xsrf" value="36424865b408db8c3f976a1a676cad60"/>'
  match_obj = re.match('.*name="_xsrf" value="(.*?)"', response.text, re.DOTALL)
  if match_obj:
    _xsrf = match_obj.group(1)
    post_data = {
      '_xsrf': _xsrf,
      'phone_num': 'xxxxxxxxxxx',
      'password': 'xxxxxxx',
      'captcha':''
    }
    t = str(int(time.time() * 1000))
    captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
    return [scrapy.Request(url=captcha_url,
                           meta={'post_data':post_data},
                           headers=self.headers,
                           callback=self.get_captcha_login)]

  else:
    raise EOFError
相關文章
相關標籤/搜索