Requests-HTML模塊

Talk is cheap,Show me your code.

官方文檔:http://html.python-requests.org

中文文檔:https://cncert.github.io/requests-html-doc-cn/#/?id=rebuild_methodprepared_request-response

GitHub:https://github.com/Liangchengdeye/Requests_Html_Spider

一、簡(jiǎn)介

1坑填、編寫爬蟲時(shí)requests+BeautifulSoup是一對(duì)完美的組合你踩,先通過requests模塊將網(wǎng)頁爬取下來伍俘,再交給BeautifulSoup等一些html解析庫進(jìn)行解析叽掘,而requests_html可以直接解析。

2道偷、優(yōu)點(diǎn)

  • 支持JavaScript
  • 支持CSS選擇器
  • 支持xpath選擇器
  • 模擬用戶代理
  • 自動(dòng)重定向
  • 連接池和cookie持久性
  • 支持異步

Tips:看文檔說這個(gè)模塊只支持py3.6缀旁,但這個(gè)庫還在更新,所以py3.6及以上版本應(yīng)該都能用勺鸦。

3并巍、安裝
pip install requests-html

二、使用

1换途、請(qǐng)求網(wǎng)頁

from requests_html import HTMLSession
session = HTMLSession()
參數(shù):
      browser.args = [
      '--no-sand',
      '--user-agent = XXXXX'
      ]

比如:
session = HTMLSession(
    browser_args=[
        '--no-sand',
        '--user-agent=計(jì)算機(jī)配置'
    ]  # , headless=False  # ??去改源碼
)

get請(qǐng)求參數(shù):
    url 【請(qǐng)求的路由】
    headers = {}  【頭部信息】 優(yōu)先級(jí)高于cookie
    params = {}  【參數(shù)】
    proxies = {'http':'http://端口:ip'}  【代理IP】
    timeout = 0.5  【網(wǎng)頁響應(yīng)超時(shí)時(shí)間】
    allow_redirects = False  【是否允許重定向懊渡,默認(rèn)True】

post請(qǐng)求參數(shù):
    url 【請(qǐng)求的路由】
    header = {}  【頭部信息】
    cookies = {} 【header中有cookie信息,另外單獨(dú)傳入cookie】
    data = {}  【post請(qǐng)求數(shù)據(jù)是放在數(shù)據(jù)體中的】
    json = {}  【json格式的數(shù)據(jù)】
    files = {'file':open(...,'rb')} 【文件數(shù)據(jù)】
    timeout = 0.5  【網(wǎng)頁響應(yīng)超時(shí)時(shí)間】
    allow_redirects = False  【是否允許重定向军拟,默認(rèn)True】
??源碼改動(dòng)3處
(1)from requests_html import HTMLSession 進(jìn)入
(2)class HTMLSession(BaseSession):
        def __init__(self, **kwargs):
            super(HTMLSession, self).__init__(**kwargs)
(3)因?yàn)槔^承的是BaseSession剃执,所以進(jìn)入BaseSession修改三處地方
將頭部寫活
添加頭部

2、響應(yīng)

url = "要請(qǐng)求的網(wǎng)頁鏈接"
響應(yīng)對(duì)象 = session.get(url=url)
響應(yīng)對(duì)象 = session.post(url=url)
響應(yīng)對(duì)象 = session.request(method='get/post',url=url)

    
響應(yīng)屬性:
  響應(yīng)對(duì)象.url 【獲取url】
  響應(yīng)對(duì)象.text  【獲取響應(yīng)文本】
  響應(yīng)對(duì)象.encoding = 'GBK/UTF_8'  【設(shè)置網(wǎng)頁編碼】
  響應(yīng)對(duì)象.content  【獲取網(wǎng)頁上的二進(jìn)制圖片懈息、視頻】
  響應(yīng)對(duì)象.json()  【獲取json格式數(shù)據(jù)】
  響應(yīng)對(duì)象.status_code  【狀態(tài)碼】
  響應(yīng)對(duì)象.headers  【獲取頭部信息】
  響應(yīng)對(duì)象.cookies 【獲取cookies信息】
  響應(yīng)對(duì)象.history  【獲取歷史信息】

3肾档、解析
這個(gè)庫是解析HTML,所以解析的都是html對(duì)象

(1) html對(duì)象屬性(值):

  響應(yīng)對(duì)象.html.absolute_links  【絕對(duì)路徑辫继,自動(dòng)添加http://怒见,自動(dòng)補(bǔ)全和其他鏈接地址一樣,返回的鏈接自動(dòng)轉(zhuǎn)為絕對(duì)路徑】
  響應(yīng)對(duì)象.html.links 【以列表形式提取姑宽、返回響應(yīng)源碼中的所有url鏈接】
  響應(yīng)對(duì)象.html.base_url  【基礎(chǔ)路徑遣耍,就是主路徑,一般是一個(gè)網(wǎng)站的網(wǎng)址】
  響應(yīng)對(duì)象.html.html  【html網(wǎng)頁】
  響應(yīng)對(duì)象.html.text  【網(wǎng)頁中的文本內(nèi)容】
  響應(yīng)對(duì)象.html.encoding  【獲取編碼方式】
  響應(yīng)對(duì)象.html.encoding='GBK'  【輸出的文本出現(xiàn)亂碼低千,這時(shí)就需要指定編碼方式配阵,??在控制臺(tái)輸入document.charset查看編碼類型】
  響應(yīng)對(duì)象.html.raw_html  【未解析過的網(wǎng)頁】
  響應(yīng)對(duì)象.html.pq  【<class 'pyquery.pyquery.PyQuery'> pyquery對(duì)象】

????(2) html對(duì)象方法:

  • 響應(yīng)對(duì)象.html.find () —— 使用css解析器
r.html.find('css選擇器')
r.html.find('css選擇器',first=True)

r.html.find('#footer')  # 查找footer標(biāo)簽元素對(duì)象
r.html.find('a',first=True)  # 查找第一個(gè)a標(biāo)簽元素對(duì)象

???find函數(shù)有5個(gè)參數(shù):
?selector【css解析式,要用的CSS選擇器】
?first 【布爾值示血,如果為真則表示獲取符合css表達(dá)式的第一個(gè)元素對(duì)象棋傍,否則返回滿足條件的元素對(duì)象列表】
?containing【如果指定,則只返回包含提供文本的元素难审,放在列表中】
?clean【布爾值瘫拣,是否消除 <script> 和<style> 標(biāo)簽對(duì)html產(chǎn)生的影響】
?_encoding【編碼方式】

???因?yàn)楹瘮?shù)獲得的是元素,所以元素還有他的屬性

----- 響應(yīng)對(duì)象.html.find().text ----
r.html.find('a', first=True).text  >>> 獲取元素的文本內(nèi)容
>>>輸出:懈婧埃花網(wǎng)
----- 響應(yīng)對(duì)象.html.find().attrs ----
r.html.find('a', first=True)  >>> 查找元素對(duì)象
r.html.find('a', first=True).attrs)  >>>獲取元素所有的屬性
r.html.find('a', first=True).attrs['href'] >>> 獲取元素的具體屬性麸拄,返回值是個(gè)字典

>>>輸出:
>>>  <Element 'a'  title='校花網(wǎng)'>
>>>  {'href': 'http://www.xiaohuar.com', 'title': '星花網(wǎng)'}
>>>  http://www.xiaohuar.com
----- 響應(yīng)對(duì)象.html.find().html ----
r.html.find('a', first=True).html  >>> 查找html內(nèi)容
>>>輸出 <a  title="&#x6821;&#x82B1;&#x7F51;">新G校花網(wǎng)</a>

??CSS選擇器:
??(1) 類名選擇器
????class ——> .類名
??(2) id選擇器
????id ——> #id名
??(3) 標(biāo)簽選擇器
????p ——> 標(biāo)簽p
??(4) 后代選擇器
????所有:兒子,孫子秆吵,重孫...
????ul li a
??(5) 子選擇器
????只有兒子
????ul li
??(6) 屬性選擇器(5種)
????[屬性] 用于選取帶有指定屬性的元素
????[屬性=值] 用于選取帶有指定屬性和值的元素
????[屬性^=值] 匹配屬性值以指定值開頭的每個(gè)元素
????[屬性$=值] 匹配屬性值以指定值結(jié)尾的每個(gè)元素
????[屬性~=值] 用于選取屬性值中包含指定詞匯的元素
????[屬性=*值] 匹配屬性值中包含指定值的每個(gè)元素
??(7) 群組選擇器
????選擇器1淮椰,選擇器2... 相當(dāng)于or
??(8) 多條選擇器
????選擇器1選擇器2... 相當(dāng)于and

更多用法:https://www.w3school.com.cn/cssref/css_selectors.asp


  • 響應(yīng)對(duì)象.html.xpath() —— 使用path解析器
r.html.xpath('xpath選擇器')  
r.html.xpath('xpath選擇器',first=True)

h.html.xpath("http://div[@id='menu']/a")
h.html.xpath("http://div[@id='menu']",first=True  

參數(shù)和屬性參照css選擇器。


??XPath選擇器
語法:
(1) 選取節(jié)點(diǎn)

表達(dá)式 描述
nodename 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)
/ 從根節(jié)點(diǎn)選取
// 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn)纳寂,而不考慮它們的位置
. 選取當(dāng)前節(jié)點(diǎn)
.. 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
@ 選取屬性

實(shí)例??

路徑表達(dá)式 結(jié)果
bookstore 選取 bookstore 元素的所有子節(jié)點(diǎn)
/bookstore 選取根元素 bookstore主穗。
注釋:假如路徑起始于正斜杠( / ),則此路徑始終代表到某元素的絕對(duì)路徑毙芜!
bookstore/book 選取屬于 bookstore 的子元素的所有 book 元素
//book 選取所有 book 子元素忽媒,而不管它們?cè)谖臋n中的位置
bookstore//book 選擇屬于 bookstore 元素的后代的所有 book 元素,而不管它們位于 bookstore 之下的什么位置
//@lang 選取名為 lang 的所有屬性

(2)謂語:用來查找某個(gè)特定的節(jié)點(diǎn)或者包含某個(gè)指定的值的節(jié)點(diǎn)
實(shí)例??

路徑表達(dá)式 結(jié)果
/bookstore/book[1] 選取屬于 bookstore 子元素的第一個(gè) book 元素
/bookstore/book[last()] 選取屬于 bookstore 子元素的最后一個(gè) book 元素
/bookstore/book[last()-1] 選取屬于 bookstore 子元素的倒數(shù)第二個(gè) book 元素
/bookstore/book[position()<3] 選取最前面的兩個(gè)屬于 bookstore 元素的子元素的 book 元素
//title[@lang] 選取所有擁有名為 lang 的屬性的 title 元素
//title[@lang='eng'] 選取所有 title 元素腋粥,且這些元素?fù)碛兄禐?eng 的 lang 屬性
/bookstore/book[price>35.00] 選取 bookstore 元素的所有 book 元素晦雨,且其中的 price 元素的值須大于 35.00
/bookstore/book[price>35.00]/title 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大于 35.00

(3) 選取未知節(jié)點(diǎn)

通配符 描述
* 匹配任何元素節(jié)點(diǎn)
@* 匹配任何屬性節(jié)點(diǎn)
node() 匹配任何類型的節(jié)點(diǎn)

實(shí)例??

路徑表達(dá)式 結(jié)果
/bookstore/* 選取 bookstore 元素的所有子元素
//* 選取文檔中的所有元素
//title[@*] 選取所有帶有屬性的 title 元素

(4) 選取若干路徑
實(shí)例??:通過在路徑表達(dá)式中使用“|”運(yùn)算符灯抛,可以選取若干個(gè)路徑

路徑表達(dá)式 結(jié)果
//book/title 豎杠 //book/price 選取 book 元素的所有 title 和 price 元素
//title 豎杠 //price 選取文檔中的所有 title 和 price 元素
/bookstore/book/title 豎杠 //price 選取屬于 bookstore 元素的 book 元素的所有 title 元素金赦,以及文檔中所有的 price 元素

更多用法:https://www.w3school.com.cn/xpath/index.asp


  • 響應(yīng)對(duì)象.html.search() —— 搜索元素的文本內(nèi)容
r.html.search('模板')  # 查出一個(gè)
r.html.search_all('模板')  # 查出所有
??:r.html.search('我覺得很有{}理')[0]  >>>輸出:道
    r.html.search('我覺得很{a}道{test}')['test']  >>>輸出:理

??tips:如果沒有找到的話返回網(wǎng)頁
  • 響應(yīng)對(duì)象.html.render() —— JavaScript支持
    內(nèi)置支持js渲染,對(duì)以往需要使用Selenium獲取源碼的頁面可不再額外使用Selenium庫操作对嚼。
    render方法將會(huì)渲染頁面的JavaScript夹抗,返回渲染后的數(shù)據(jù)。
    特別注意的是:在初次使用該功能的時(shí)候會(huì)自動(dòng)下載支持包:Chromium
from requests_html import HTMLSession

session = HTMLSession()
r = session.get('http://python-requests.org/')
r.html.render()

??render()方法可用參數(shù):
??retries 【在Chromium里加載頁面的重試次數(shù)】
??script 【執(zhí)行頁面上的JavaScript (可選參數(shù)) 】
??wait 【頁面加載前的等待時(shí)間纵竖,防止超時(shí) (單位:秒漠烧,可選參數(shù)) 】
??scrolldown 【接收整數(shù)參數(shù)n,如果提供參數(shù)n靡砌,表示向后翻n頁】
??sleep 【在頁面初次渲染之后的等待時(shí)間】
??reload 【如果為False已脓,則不會(huì)重新從瀏覽器加載內(nèi)容,而是讀取內(nèi)存里的內(nèi)容】
??keep_page 【如果為True通殃,將會(huì)允許你通過r.html.page與瀏覽器頁面交互】

??Tips:如果scrolldown和sleep都指定度液,那么程序會(huì)在暫停相應(yīng)時(shí)間后厕宗,再往后翻頁面(如:scrolldown=10, sleep=1)

scripy:"""( ) => {
?       js代碼
?       js代碼
?       }
?       """
?       scrolldow:n
?       sleep:n
?       keep_page:True/False
()=>{
Object.defineProperties(navigator,{
        webdriver:{
        get: () => undefined
        }
    })

??與瀏覽器交互
(1) 頁面事件 —— r.html.page.XXX

----- 格式 -----
async def 函數(shù)名():  # 先定義一個(gè)函數(shù)
    await r.html.page.XXX  # 交互方式
session.loop.run_until_complete(函數(shù)名())  # 調(diào)用

 ----- 交互方式 -----
r.html.page.screenshot({"path":路徑})  # 截屏
r.html.page.evaluate("""()=>{js代碼}""")  
r.html.page.cookies()
r.html.page.type('css選擇器','內(nèi)容',{'delay':100})
r.html.page.click('css選擇器')  # 點(diǎn)擊
r.html.page.focus('css選擇器')  # 聚焦
r.html.page.hover('css選擇器')  # 懸浮
r.html.page.waitForSelector('css選擇器')
r.html.page.waitFor(1000)  # 等待

(2) 鍵盤事件 —— r.html.page.keyboard.XXX

r.html.page.keyboard.type('咸魚今天努力了沒',{'delay':100})  # 鍵盤打字
r.html.page.keyboard.up('Shift')  # Shift抬起,按鍵可以換成別的
r.html.page.keyboard.down('Shift')  # Shift按下
r.html.page.keyboard.press('ArrowLeft')  # 一直按左鍵進(jìn)行選擇

(3) 鼠標(biāo)事件 —— r.html.page.mouse.XXX

r.html.page.mouse.click(x,y,{  # 點(diǎn)擊
    'button':'left',
    'click':1
    'delay':0
})
r.html.page.mouse.down({'button':'left'})  # 鼠標(biāo)按下
r.html.page.mouse.up({'button':'left'}) # 鼠標(biāo)抬起
??一般up和down一起使用堕担,表示點(diǎn)擊一下
r.html.page.mouse.movie(x,y,{'steps':1})  # 鼠標(biāo)移動(dòng)已慢,步長為1表示移動(dòng)一步就到,步長設(shè)置的越大霹购,則步數(shù)越細(xì)佑惠,移動(dòng)越慢

練習(xí):

from requests_html import HTMLSession

session = HTMLSession(
    browser_args=[
        '--no-sand',
        '--user-agent=自己的電腦配置'
    ]  # , headless=False  # ??去改源碼
)

url = 'http://www.google.com'
# r = session.request(method='get', url=url)
# print(dir(r.html.find('a',first=True)))
#
# a_element = r.html.find('#footer',first=True)
# print(a_element.attrs['name'])
# print(r.html.search_all('(提示:{name},最新章節(jié)可能會(huì){pwd}齐疙,登錄書架即可實(shí)時(shí)查看膜楷。)')[0])

r = session.request(method='get', url='https://www.bilibili.com/')

scrapts = """
    ()=>{
        Object.defineProperties(navigator,{
        webdriver:{
        get:() => undefined
        }
    })}
"""

try:
    r.html.render(script=scrapts, sleep=1, keep_page=True)


    async def main():
        await r.html.page.screenshot({"path": '1.png', 'clip': {'x': 200, 'y': 200, 'width': 400, 'height': 400}})
        res = await r.html.page.evaluate("""
        ()=>{
            var a = document.querySelector("#list")
            return {'x':a.offsetLeft}
        }
        """)
        print(res)
        print(await r.html.page.cookies())
        await r.html.page.type('#kw', '瀧澤蘿拉', {'delay': 500})
        await r.html.page.waitForSelector('[name="tj_trnews"]')
        await r.html.page.click('[name="tj_trnews"]')
        await r.html.page.focus('[type="number"]')
        await r.html.page.keyboard.type('111', {'delay': 200})
        await r.html.page.hover('[data-stat-id="6f5c93b4d1baf5e9"]')
        await r.html.page.keyboard.type('喜歡你啊', {'delay': 200})
        await r.html.page.keyboard.down('Shift')
        for i in range(3):
            await r.html.page.keyboard.press('ArrowLeft', {'delay': 1000})
        await r.html.page.keyboard.up('Shift')
        await r.html.page.keyboard.up('Backspace')
        res = await r.html.page.evaluate('''
        ()=>{
            car a = document.querySelector('[alt="【究極爆肝】德克薩斯與拉普蘭德的感傷往事(明日方舟描改 動(dòng)畫手書·完整版)"]')
            return {
                'x':a.x+a.width/2,
                'y':a.y+a.height/2
            }
        }
        ''')
        print(res)
        await r.html.page.mouse.movie(res['x'], res['y'], {'step': 200})
        await r.html.page.mouse.down({'button': 'right'})
        await r.html.page.mouse.up({'button': 'right'})
        await r.html.page.mouse.click(res['x'], res['y'])

        await r.html.page.waitFor(5000)
    session.loop.run_until_complete(main())
finally:
    session.close()

實(shí)戰(zhàn):

1、姓攴埽花網(wǎng)圖片
# 對(duì)頁碼進(jìn)行分析
# http://www.xiaohuar.com/hua/
# http://www.xiaohuar.com/list-1-1.html  第2頁
# http://www.xiaohuar.com/list-1-2.html  第3頁

import os
from requests_html import HTMLSession

# 生成所有頁碼url
def get_page_url():
    for i in range(46):
        yield 'http://www.xiaohuar.com/list-1-{}.html'.format(i)

session = HTMLSession()

# 第一頁解析測(cè)試
url = "http://www.xiaohuar.com/list-1-0.html"

# 解析頁面赌厅,獲取圖片名和url
def parse_page(url):
    r = session.request(method='get', url=url)
    img_element_list = r.html.find('[class="img"] img')
    for img_element in img_element_list:
        file_name1 = img_element.attrs.get('alt').replace('/', '').replace('\\', '')
        # print(file_name)
        file_name = file_name1 + '.png'
        file_url: str = img_element.attrs.get('src')
        file_url = r.html.base_url[:-1] + file_url if not file_url.startswith("http") else file_url
        save_file(file_name, file_url)

# 保存圖片
def save_file(name, url):
    base_path = '校花圖片'
    file_path = os.path.join(base_path, name)
    r = session.get(url=url)
    with open(file_path, 'wb') as f:
        f.write(r.content)
        print('%s下載成功' % name)


if __name__ == '__main__':
    for page_url in get_page_url():
        parse_page(page_url)
2轿塔、胁於祝花網(wǎng)視頻
"""
分析:校花網(wǎng)視頻分為兩種催训,一種是mp4格式的洽议,一種是m3u8格式的,所以要分別進(jìn)行處理
"""
from requests_html import HTMLSession
import os

session = HTMLSession()

# 獲取索引頁url
def get_index_page():
    for i in range(6):
        url = 'http://www.xiaohuar.com/list-3-%s.html' % i
        yield url

# 解析索引頁獲取詳情頁url
# 解析詳情頁
def get_detail_page(url):
    r = session.get(url=url)
    for element in r.html.find('#images a[class="imglink"]'):
        yield element.attrs.get('href')

# 解析詳情頁獲取視頻url漫拭,名字
# 獲得名字亚兄,類型,鏈接
def get_url_name(url):
    r = session.get(url=url)
    r.html.encoding = 'gbk'
    file_name = r.html.find("title", first=True).text.replace('\\', '')
    print(file_name)
    element = r.html.find('#media source', first=True)
    if element:
        vurl = element.attrs.get('src')
        vtype = 'mp4'
    else:
        vurl = r.html.search('var vHLSurl    = "{}";')[0]
        vtype = 'm3u8'
    return file_name, vurl, vtype


# 保存文件
def save(file_name, vurl, vtype):
    if vtype == "mp4":
        file_name += ".mp4"
        r = session.get(url=vurl)
        with open(file_name, 'wb') as f:
            f.write(r.content)
    elif vtype == "m3u8":
        save_m3u8(file_name, vurl)


# 處理m3u8
# save_m3u8('xxx','https://www6.laqddcc.com/hls/2019/05/05/BRsIeDpx/playlist.m3u8')
def save_m3u8(file_name, vurl):
    if not os.path.exists(file_name):
        os.mkdir(file_name)
    r = session.get(url=vurl)
    m3u8_path = os.path.join(file_name, 'playlist.m3u8')
    with open(m3u8_path, 'wb') as f:
        f.write(r.content)
    for line in r.text:
        if line.endswith('ts'):
            ts_url = vurl.replace('playlist.m3u8', line)
            ts_path = os.path.join(file_name, line)
            r0 = session.get(url=ts_url)
            with open(ts_path, 'wb') as f:
                f.write(r0.content)


if __name__ == '__main__':
    for index_page in get_index_page():
        for detail_url in get_detail_page(index_page):
            file_name, vurl, vtype = get_url_name(detail_url)
            save(file_name, vurl, vtype)
3采驻、模擬知乎登錄
"""
分析:知乎用密碼登錄审胚,總共發(fā)送3次請(qǐng)求,請(qǐng)求路由相同礼旅,但請(qǐng)求方式不同膳叨;驗(yàn)證碼有兩種方式,字母驗(yàn)證碼和選擇倒立文字驗(yàn)證碼痘系;兩個(gè)加密菲嘴,formdata加密和signature加密。
     3次請(qǐng)求:【第一次】https://www.zhihu.com/api/v3/oauth/captcha?lang=en  get請(qǐng)求檢測(cè)是否需要驗(yàn)證碼,傳輸?shù)氖莏son格式汰翠;
             【第二次】https://www.zhihu.com/api/v3/oauth/captcha?lang=en  put獲取驗(yàn)證碼龄坪,返回的是base64格式的驗(yàn)證碼;
             【第三次】https://www.zhihu.com/api/v3/oauth/captcha?lang=en  post請(qǐng)求發(fā)送驗(yàn)證碼复唤。
     兩種驗(yàn)證碼:lang=en 英文健田;lang=cn 中文。
     signature加密是使用sha1和hmac佛纫;
     formdata加密是通過導(dǎo)入加密的js函數(shù)來反解出的妓局。
"""
import requests
import base64
import Image
from time import sleep
import hmac
from hashlib import sha1
import time
from urllib.parse import urlencode
import execjs
import json


class Zhihu(object):
    def __init__(self):
        self.session = requests.session()
        self.headers = {
            'referer': 'https://www.zhihu.com/signin?next=%2F',
            'user-agent': '自己的電腦配置'
        }
        self.picture = None  # 存驗(yàn)證碼
        self.signature = None  # 存簽名
        self.picture_url = None  # 存驗(yàn)證碼鏈接

    def getbasecookie(self):
        self.session.get(url='https://www.zhihu.com/signin?next=%2F', headers=self.headers)
        self.session.get(url='https://www.zhihu.com/api/v4/search/preset_words', headers=self.headers)
        # self.session.post(url='https://www.zhihu.com/udid', headers=self.headers)  # 未知

    def getcapture(self):
        # 獲取驗(yàn)證碼方法总放,有時(shí)候不用獲取驗(yàn)證碼就可以直接登錄
        # lang=en是英文字母,lang=cn是選倒過來的文字
        message = self.session.get(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en',
                                   headers=self.headers).json()  # get請(qǐng)求檢測(cè)是否需要驗(yàn)證碼,傳輸?shù)氖莏son格式
        print(message)  # {'show_captcha':True/False}
        if message['show_captcha'] == False:  # 如果不需要驗(yàn)證碼
            self.picture = ''
        else:
            self.picture_url = self.session.put(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en',
                                                headers=self.headers).json()  # put獲取驗(yàn)證碼好爬,返回的是base64格式的驗(yàn)證碼
            # 采用base64格式將驗(yàn)證碼通過圖片格式顯示出來
            with open('captcha.jpg', 'wb') as f:
                f.write(base64.b64decode(self.picture_url['img_base64']))
            image = Image.open('captcha.jpg')
            image.show()
            self.picture = input('請(qǐng)輸入驗(yàn)證碼:')
            sleep(2)
            message1 = self.session.post(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en',data={'input_text':self.picture},headers=self.headers).json()  # post請(qǐng)求發(fā)送驗(yàn)證碼
            print(message1)

    def get_signature(self):
        # 知乎登錄的主要問題在于找到signature间聊,重點(diǎn)
        a = hmac.new('d1b964811afb40118a12068ff74a12f4'.encode('utf-8'),digestmod=sha1)
        a.update('password'.encode('utf-8'))
        a.update(b'c3cef7c66a1843f8b3a9e6a1e3160e20')
        a.update(b'com.zhihu.web')
        a.update(str(int(time.time()*1000)).encode('utf-8'))
        self.signature = a.hexdigest()

    def Login_phone(self):
        # 登錄
        data = {
            'client_id': 'c3cef7c66a1843f8b3a9e6a1e3160e20',
            'grant_type': 'password',
            'timestamp': str(int(time.time() * 1000)),
            'source': 'com.zhihu.web',
            'signature': self.signature,
            'username': '+8615151979063',
            'password': '88404620wpr',
            'captcha': self.picture,
            'lang': 'en',
            'utm_source': '',
            'ref_source': 'other_https://www.zhihu.com/signin?next=%2F',
        }

        headers = {
            'scheme': 'https',
            'accept': '*/*',
            'accept-encoding': 'gzip, deflate, br',
            'accept-language': 'zh-CN,zh;q=0.8',
            'cache-control': 'no-cache',
            # 'content-length':'412',
            'pragma': 'no-cache',
            'origin': 'https://www.zhihu.com',
            'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0',
            'content-type': 'application/x-www-form-urlencoded',
            'referer': 'https://www.zhihu.com/signin?next=%2F',
            'x-xsrftoken': self.session.cookies.get('_xsrf'),
            'x-requested-with': 'fetch',
            'x-ab-param': 'top_vipconsume=1;se_famous=1;se_featured=1;top_ebook=0;top_recall_exp_v1=1;se_topicdirect=2;li_ts_sample=old;qa_answerlist_ad=0;zr_ans_rec=gbrank;se_likebutton=0;se_d2q=0;top_root=0;pf_noti_entry_num=0;li_android_vip=0;se_limit=0;se_ltr_nn=0;se_time_threshold=0;top_gr_ab=0;pf_fuceng=1;ls_videoad=0;top_ydyq=X;qa_test=0;zr_art_rec=base;se_topiclabel=1;top_recall_exp_v2=1;ls_new_upload=0;zr_km_answer=open_cvr;se_webtimebox=0;se_backsearch=0;tp_meta_card=0;zr_search_xgb=0;zr_km_xgb_model=new_xgb;se_spb309=0;soc_special=0;li_album3_ab=0;li_se_xgb=0;se_p_slideshow=0;ls_fmp4=0;soc_bignew=1;soc_bigone=0;ug_zero_follow_0=0;zr_article_rec_rank=close;zr_km_paid_answer=0;se_ri=0;tp_sft_v2=d;zr_rec_answer_cp=close;se_agency= 0;tsp_hotctr=1;soc_notification=0;pf_foltopic_usernum=50;zr_video_rank=new_rank;se_whitelist=0;tp_sft=a;tp_header_style=1;ug_zero_follow=0;li_se_paid_answer=0;se_go_ztext=0;tp_topic_head=1;top_reason=1;li_qa_new_cover=0;se_expired_ob=0;top_recall_deep_user=1;tsp_lastread=0;li_qa_cover=old;li_price_test=1;tp_qa_metacard_top=top;se_rr=0;se_wannasearch=0;se_subtext=0;pf_creator_card=1;zr_km_tag=open;se_mclick1=0;se_movietab=1;top_v_album=1;ug_newtag=0;zr_km_slot_style=event_card;se_page_limit_20=1;se_zu_recommend=0;top_rank=0;zr_intervene=0;se_billboardsearch=0;se_new_topic=0;se_payconsult=0;soc_update=1;pf_feed=1;zr_answer_rec_cp=open;se_ltr_ck=0;tp_qa_metacard=1;top_universalebook=1;se_websearch=3;ug_goodcomment_0=1;ug_follow_answerer=0;zr_infinity_small=256;se_mclick=0;top_native_answer=1;li_hot_score_ab=0;zr_rel_search=base;zr_video_recall=current_recall;se_ad_index=10;se_college_cm=0;ug_fw_answ_aut_1=0;zr_video_rank_nn=new_rank;se_college=default;se_search_feed=N;ug_follow_topic_1=2;li_back=0;se_webrs=1;se_amovietab=1;top_new_feed=5;li_pay_banner_type=0;li_ebook_detail=1;se_preset_tech=0;se_colorfultab=1;tp_sticky_android=0;li_tjys_ec_ab=0;ug_follow_answerer_0=0;li_album_liutongab=0;li_se_kv=0;se_mobileweb=1;top_quality=0;se_lottery=0;top_test_4_liguangyi=1;zr_km_style=base;se_ios_spb309=0;se_auto_syn=0;tsp_vote=1;pf_newguide_vertical=0;tsp_childbillboard=1;li_se_album_card=0;se_ltr_gc=0;tp_qa_toast=1;tp_m_intro_re_topic=1;se_waterfall=0;top_hotcommerce=1;zr_infinity_a_u=close;se_webmajorob=0;se_zu_onebox=0;se_site_onebox=0',
            'x-zse-83': '3_2.0',
        }
        print(self.session.cookies.get('_xsrf'))
        print(urlencode(data))

        with open('知乎加密js.js','r',encoding='utf-8') as f:
            js = execjs.compile(f.read())  # 傳入unicode字符
            data = js.call(u'b',urlencode(data))  # data_dict為表單數(shù)據(jù)
            print(data)
        message = self.session.post(url='https://www.zhihu.com/api/v3/oauth/sign_in',headers=headers,data=data)
        message.encoding='utf-8'
        print(message.text)
        print(json.loads(message.text)['error']['message'])

    def target_url(self,url):
        text = self.session.get(url)
        return text.text


if __name__ == '__main__':
    zhihu = Zhihu()
    zhihu.getbasecookie()  # 首次cookie
    zhihu.getcapture()  # 驗(yàn)證碼
    zhihu.get_signature()  # signature
    zhihu.Login_phone()  # 登錄
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抵拘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌型豁,老刑警劉巖僵蛛,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異迎变,居然都是意外死亡充尉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門衣形,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驼侠,“玉大人,你說我怎么就攤上這事谆吴〉乖矗” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵句狼,是天一觀的道長笋熬。 經(jīng)常有香客問我,道長腻菇,這世上最難降的妖魔是什么胳螟? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮筹吐,結(jié)果婚禮上糖耸,老公的妹妹穿的比我還像新娘。我一直安慰自己丘薛,他們只是感情好嘉竟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洋侨,像睡著了一般周拐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凰兑,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天妥粟,我揣著相機(jī)與錄音,去河邊找鬼吏够。 笑死勾给,一個(gè)胖子當(dāng)著我的面吹牛滩报,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播播急,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼脓钾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了桩警?” 一聲冷哼從身側(cè)響起可训,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捶枢,沒想到半個(gè)月后握截,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烂叔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年谨胞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒜鸡。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胯努,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逢防,到底是詐尸還是另有隱情叶沛,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布忘朝,位于F島的核電站恬汁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏辜伟。R本人自食惡果不足惜氓侧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望导狡。 院中可真熱鬧约巷,春花似錦、人聲如沸旱捧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枚赡。三九已至氓癌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贫橙,已是汗流浹背贪婉。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卢肃,地道東北人疲迂。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓才顿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尤蒿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子郑气,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354