Python結合BeautifulSoup抓取知乎數據

本文主要介紹利用Python登錄知乎賬號,抓取其中的用戶名、用戶頭像、知乎的問題、問題來源、被贊數目、以及回答者。其中數據是配合Beautiful Soup進行解析的。
首先,要解決的是知乎登錄問題。在程序中登錄知乎我們直接提供用戶名和密碼是無法進行登錄的,這裏我們採用一個比較笨拙的辦法直接在發送請求過程中附帶上cookies。這個cookies值我們可以通過在火狐瀏覽器登錄知乎時用firebug直接捕獲。cookies獲取如下圖所示:

firebug獲取火狐cookies

   [info]
email =youremail
password = youpassword

[cookies]
q_c1 =
cap_id =
_za =
__utmt =
__utma =
__utmb =
__utmc =
__utmz =
__utmv =
z_c0 =
unlock_ticket = 

然後我們可以利用python的requests模塊、urllib、urllib2模塊實現如下登錄代碼:

#知乎登錄
def create_session():
    cf = ConfigParser.ConfigParser()
    cf.read('config.ini')
    #從配置文件獲取cookies值,並轉化爲dict
    cookies = cf.items('cookies')
    cookies = dict(cookies)
    from pprint import pprint
    pprint(cookies)
    #獲取登錄名
    email = cf.get('info', 'email')
    #獲取登錄密碼
    password = cf.get('info', 'password')

    session = requests.session()
    login_data = {'email': email, 'password': password}
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) 

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 

Safari/537.36',
        'Host': 'www.zhihu.com',
        'Referer': 'http://www.zhihu.com/'
    }
    #post登錄
    r = session.post('http://www.zhihu.com/login/email', data=login_data, 

headers=header)
    if r.json()['r'] == 1:
        print 'Login Failed, reason is:',
        for m in r.json()['data']:
            print r.json()['data'][m]
        print 'So we use cookies to login in...'
        has_cookies = False
        for key in cookies:
            if key != '__name__' and cookies[key] != '':
                has_cookies = True
                break
        if has_cookies is False:
            raise ValueError('請填寫config.ini文件中的cookies項.')
        else:
            r = session.get('http://www.zhihu.com/login/email', 
cookies=cookies) # 用cookies登錄


    return session, cookies
登錄是否成功我們可以查看保存的請求返回的網頁是否包含登錄用戶名。登錄成功後我們利用BeautifulSoup 的構造方法將請求後獲得的知乎頁面文檔進行構造得到一個文檔的對象。這個轉換過程中首先,文檔被轉換成Unicode,並且HTML的實例都被轉換成Unicode編碼,然後,Beautiful Soup選擇最合適的解析器來解析這段文檔,如果手動指定解析器那麼Beautiful Soup會選擇指定的解析器來解析文檔。Beautiful Soup將複雜HTML文檔轉換成一個複雜的樹形結構,每個節點都是Python對象。我們可以通過這些節點結合原始HTML文件來提取我們需要的內容。如下圖所示,是我們獲取登錄用戶名和部分知乎問題在html文檔中對應的部分。

    我們完整的抓取以及數據提取代碼如下所示:

用戶名對應html代碼部分
知乎問題對應HTML代碼部分

    # -*- coding: utf-8 -*-
'''
網絡爬蟲之用戶名密碼及驗證碼登陸:爬取知乎網站
'''
import requests
import ConfigParser
from bs4 import BeautifulSoup
import re
import urllib
import urllib2

def create_session():
    cf = ConfigParser.ConfigParser()
    cf.read('config.ini')
    #從配置文件獲取cookies值,並轉化爲dict
    cookies = cf.items('cookies')
    cookies = dict(cookies)
    from pprint import pprint
    pprint(cookies)
    #獲取登錄名
    email = cf.get('info', 'email')
    #獲取登錄密碼
    password = cf.get('info', 'password')

    session = requests.session()
    login_data = {'email': email, 'password': password}
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) 

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 

Safari/537.36',
        'Host': 'www.zhihu.com',
        'Referer': 'http://www.zhihu.com/'
    }
    #post登錄
    r = session.post('http://www.zhihu.com/login/email', data=login_data, 

headers=header)
    if r.json()['r'] == 1:
        print 'Login Failed, reason is:',
        for m in r.json()['data']:
            print r.json()['data'][m]
        print 'So we use cookies to login in...'
        has_cookies = False
        for key in cookies:
            if key != '__name__' and cookies[key] != '':
                has_cookies = True
                break
        if has_cookies is False:
            raise ValueError('請填寫config.ini文件中的cookies項.')
        else:
            r = session.get('http://www.zhihu.com/login/email', 

cookies=cookies) # 用cookies登錄


    return session, cookies


if __name__ == '__main__':
    requests_session, requests_cookies = create_session()
    url = 'http://www.zhihu.com'
    reqs= requests_session.get(url, cookies=requests_cookies) # 已登陸
    content=reqs.content
    #保存整個內容爲html頁面
    with open('url.html', 'w') as fp:
        fp.write(content)
    soup=BeautifulSoup(content)
    #獲取登錄用戶名
    user_name=soup.find("div",class_="top-nav-profile").a.span.string
    print "user_name:%s" % (user_name)
    #獲取用戶頭像地址
    pic_url=soup.find("div",class_="top-nav-profile").a.img
    #下載用戶頭像
  urllib.urlretrieve(pic_url['src'],'/home/zeus/pic1/'+'1.jpg')
    print "potos:%s" %(pic_url['src'])
    #獲取前10個話題的內容
    for topic in soup.find_all("div",class_="feed-main",limit=10):
    print '-------------------------------------------------------'
    #獲取知乎問題來源
    topic_source=topic.find("div",class_="feed-source").a.get_text()
    print "topic source:%s" %(topic_source)
    #獲取知乎問題
    question=topic.find("div",class_="content").a.get_text()
    print "question:%s" %(question)
    #獲取該問題被贊次數
    votecount=topic.find("div",class_="zm-item-vote").a.get_text()
    print "votecount:%s" %(votecount)
        #獲取問題回答者的用戶名
    answer=topic.find("div",class_="zm-item-rich-text js-collapse-

body")
    if answer:
        print "answer_name:%s" %(answer['data-author-name'])
    print '-------------------------------------------------------'

我們運行代碼得到如下結果:
抓取的知乎數據
對比瀏覽器頁面的知乎數據:
原始頁面的信息

抓取並保存的用戶頭像放在機器:/home/zeus路徑下pic1文件夾下,圖片名1.jpg。
這裏寫圖片描述

可見我們的程序確實成功抓取到了登錄用戶的知乎數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章