—————————如有疑問,歡迎交流指正————————
第6關(guān)
練習(xí)-儲(chǔ)存電影信息-參考
第一步:分析問題,明確結(jié)果
問題需求就是把豆瓣TOP250里面的 序號(hào)/電影名/評(píng)分/推薦語/鏈接 都爬取下來,結(jié)果是存儲(chǔ)在csv和Excel中
【講解】
問題需求就是把豆瓣TOP250里面的 序號(hào)/電影名/評(píng)分/推薦語/鏈接 都爬取下來,結(jié)果是存儲(chǔ)在csv和Excel中
這里拓展一下如何取標(biāo)簽???~
https://shimo.im/docs/QWQJYGw8CtcwQwyq/ 《豆瓣250爬蟲思路詳解》
第二步:書寫爬蟲代碼
回顧下第三關(guān)的爬蟲代碼
【解答】
選擇語言
import requests,bs4
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = bs4.BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
num = titles.find('em',class_='').text
title = titles.find('span', class_='title').text
comment = titles.find('span',class_='rating_num').text
url_movie = titles.find('a')['href']
if titles.find('span',class_='inq') != None:
tes = titles.find('span',class_='inq').text
print(num + '.' + title + '——' + comment + '\n' + '推薦語:' + tes +'\n' + url_movie)
else:
print(num + '.' + title + '——' + comment + '\n' +'\n' + url_movie)
第三步: 完善代碼,用Excel存儲(chǔ)信息
要存儲(chǔ)在Excel中呢,需要先創(chuàng)建工作表,重命名,再設(shè)置表頭,把爬取的信息寫成列表,然后用append函數(shù)多行寫入Excel,最后命名保存這個(gè)Excel 文件。
請(qǐng)改寫下方的爬蟲代碼,實(shí)現(xiàn)使用Excel存儲(chǔ)信息。
【解答】
選擇語言
import requests, bs4, openpyxl
wb=openpyxl.Workbook()
#創(chuàng)建工作薄
sheet=wb.active
#獲取工作薄的活動(dòng)表
sheet.title='movies'
#工作表重命名
sheet['A1'] ='序號(hào)' #加表頭,給A1單元格賦值
sheet['B1'] ='電影名' #加表頭,給B1單元格賦值
sheet['C1'] ='評(píng)分' #加表頭,給C1單元格賦值
sheet['D1'] ='推薦語' #加表頭,給D1單元格賦值
sheet['E1'] ='鏈接' #加表頭,給E1單元格賦值
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = bs4.BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
num = titles.find('em',class_='').text
title = titles.find('span', class_='title').text
comment = titles.find('span',class_='rating_num').text
url_movie = titles.find('a')['href']
if titles.find('span',class_='inq') != None:
tes = titles.find('span',class_='inq').text
sheet.append([num, title, comment, tes, url_movie])
# 把num, title, comment, tes和url_movie寫成列表,用append函數(shù)多行寫入Excel
print(num + '.' + title + '——' + comment + '\n' + '推薦語:' + tes +'\n' + url_movie)
else:
sheet.append([num, title, comment, None,url_movie])
print(num + '.' + title + '——' + comment + '\n' +'\n' + url_movie)
wb.save('movieTop250.xlsx')
#最后保存并命名這個(gè)Excel文件
第四步:另辟蹊徑,用csv格式存儲(chǔ)信息
思考下如何用csv創(chuàng)建寫入存儲(chǔ)呢?
請(qǐng)修改下方代碼,實(shí)現(xiàn)使用csv存儲(chǔ)信息。
【提示】
選擇語言
import requests, bs4, csv
#引用csv模塊。
csv_file=open('movieTop250.csv', 'w', newline='')
#調(diào)用open()函數(shù)打開csv文件,傳入?yún)?shù):文件名“movieTop250.csv”、寫入模式“w”、newline=''
【解答】
選擇語言
import requests, bs4, csv
#引用csv模塊。
csv_file=open('movieTop250.csv', 'w', newline='')
#調(diào)用open()函數(shù)打開csv文件,傳入?yún)?shù):文件名“movieTop250.csv”、寫入模式“w”、newline=''。
writer = csv.writer(csv_file)
# 用csv.writer()函數(shù)創(chuàng)建一個(gè)writer對(duì)象。
writer.writerow(['序號(hào)', '電影名', '評(píng)分', '推薦語', '鏈接'])
#調(diào)用writer對(duì)象的writerow()方法,可以在csv文件里寫入title:'序號(hào)', '電影名', '評(píng)分', '推薦語', '鏈接'
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = bs4.BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
num = titles.find('em',class_='').text
title = titles.find('span', class_='title').text
comment = titles.find('span',class_='rating_num').text
url_movie = titles.find('a')['href']
if titles.find('span',class_='inq') != None:
tes = titles.find('span',class_='inq').text
# 把num, title, comment, tes和url_movie寫成列表,用append函數(shù)多行寫入Excel
writer.writerow([num + '.' + title + '——' + comment + '\n' + '推薦語:' + tes +'\n' + url_movie])
else:
writer.writerow([num + '.' + title + '——' + comment + '\n' +'\n' + url_movie])
csv_file.close()
記得出現(xiàn)亂碼的問題,可以看這里的解決方法哦~
https://shimo.im/docs/hqTrdqwQhCJGktWV/ 《爬蟲第6關(guān)常見問題解決方法》
第7關(guān)
練習(xí)-做個(gè)測(cè)單詞的小工具-參考
第一步:分析需求,明確目標(biāo)
扇貝網(wǎng):https://www.shanbay.com/已經(jīng)有一個(gè)測(cè)單詞量的功能,我們要做的就是把這個(gè)功能復(fù)制下來,并且做點(diǎn)改良,搞一個(gè)網(wǎng)頁版沒有的功能 ———— 自動(dòng)生成錯(cuò)詞本。
在這一步,請(qǐng)閱讀文檔的同時(shí)打開瀏覽器的扇貝網(wǎng),跟著我一步步來。
【提示】
這里是扇貝網(wǎng)的測(cè)單詞量的界面:
??
想要復(fù)制功能,就先做分析,這個(gè)網(wǎng)頁是怎樣的工作流程。
所以,先體驗(yàn)全程,大概分為如下五個(gè)頁面:
??
??
??
??
??
先看源代碼里是否有我們的單詞。倘若有,就用find()/find_all()定位提取需要的數(shù)據(jù);
沒有的話,就要調(diào)用【檢查】-【Network】 - 【XHR】 - 找數(shù)據(jù)。
在Headers里看網(wǎng)址,在Preview里看內(nèi)容。
??
??
如圖:category/這一個(gè)XHR,用的是Get請(qǐng)求方式,訪問了網(wǎng)址https://www.shanbay.com/api/v1/vocabtest/category/,下載了一個(gè)字典。
其中“data”里面,藏了十個(gè)元素。這十個(gè)元素,里面對(duì)應(yīng)的內(nèi)容,就是我們最開始要選擇的“詞匯范圍”。
十個(gè)元素,每個(gè)里面都有兩個(gè)內(nèi)容。0是什么暫時(shí)還不知道,先放著。1是我們?cè)~匯范圍沒錯(cuò)。
比如我們選擇高考,那么在第2個(gè)元素里就有一個(gè)0是“NCEE”,有一個(gè)1是“高考”。
我們接著看下一個(gè)XHR:
??
這個(gè)圖片說明:?category=NCEE 這一個(gè)XHR,訪問了網(wǎng)址https://www.shanbay.com/api/v1/vocabtest/vocabularies/?category=NCEE
在此,“NCEE”出現(xiàn)了兩次:這個(gè)XHR的名字里面有“NCEE”,它訪問的網(wǎng)址里面也有“NCEE”。
這就揭示了一種對(duì)應(yīng)關(guān)系:當(dāng)我們選擇“高考”詞庫,那么下一個(gè)XHR,訪問的網(wǎng)址就會(huì)是用“NCEE”來結(jié)尾。
可以多試幾個(gè)詞庫驗(yàn)證下我們的猜測(cè),的確里面的對(duì)應(yīng)關(guān)系是一致的??佳泻蚇GEE一組,四級(jí)和CET4一組,六級(jí)和CET6一組。
第1個(gè)XHR,所訪問的網(wǎng)址規(guī)律就是:'https://www.shanbay.com/api/v1/vocabtest/vocabularies/?category='+'你選擇的詞庫,對(duì)應(yīng)的代碼'。
??
如圖,它下載到的是一個(gè)字典。字典里,包含了用來測(cè)試詞匯量的50個(gè)單詞。
第0,它先給出單詞。
第1,它給出四個(gè)不同的翻譯,每個(gè)翻譯都有一個(gè)對(duì)應(yīng)的pk值和rank值。
第2,它再給出一組pk值和rank值。它們,和正確翻譯里面的pk值與rank值一致。
那么,我們就可以理清楚,這個(gè)網(wǎng)頁的工作邏輯。如下圖:
??
到這里,我們就完成了至關(guān)重要的“需求分析”這個(gè)步驟。
第二步:分步講解,書寫代碼 (??????) ?
??
【講解】
下面,我將帶你一步步完成代碼。
(0). 選擇題庫。
寫這個(gè)程序,要用到requests模塊。
先用requests下載鏈接,再用res.json()解析下載內(nèi)容。
讓用戶選擇想測(cè)的詞庫,輸入數(shù)字編號(hào),獲取題庫的代碼。
提示:記得給input前面加一個(gè)int()來轉(zhuǎn)換數(shù)據(jù)類型
【解答】
選擇語言
import requests
lin=requests.get('https://www.shanbay.com/api/v1/vocabtest/category/')
#先用requests下載鏈接。
js_link = lin.json()
#解析下載得到的內(nèi)容。
bianhao = int(input('''請(qǐng)輸入你選擇的詞庫編號(hào),按Enter確認(rèn)
1,GMAT 2,考研 3,高考 4,四級(jí) 5,六級(jí)
6,英專 7,托福 8,GRE 9,雅思 10,任意
>'''))
#讓用戶選擇自己想測(cè)的詞庫,輸入數(shù)字編號(hào)。int()來轉(zhuǎn)換數(shù)據(jù)類型
ciku = js_link['data'][bianhao-1][0]
print(ciku)
(1). 根據(jù)選擇的題庫,獲取50個(gè)單詞。
第0步我們已經(jīng)拿到鏈接,這步直接用requests去下載,re.json()解析即可。
【解答】
選擇語言
test = requests.get('https://www.shanbay.com/api/v1/vocabtest/vocabularies/?category='+ciku)
#下載用于測(cè)試的50個(gè)單詞。
words = test.json()
#對(duì)測(cè)試的單詞進(jìn)行解析。
print(words)
(2). 讓用戶選擇認(rèn)識(shí)的單詞:此處,要分別記錄下用戶認(rèn)識(shí)哪些,不認(rèn)識(shí)哪些。
已經(jīng)有了單詞數(shù)據(jù),提取出來讓用戶識(shí)別,并記錄用戶認(rèn)識(shí)哪些不認(rèn)識(shí)哪些,至少2個(gè)list來記錄。
50個(gè)單詞,記得要用循環(huán)。用戶手動(dòng)輸入自己的選擇,用input() 。我們要識(shí)別用戶的輸入,并基于此決定把這個(gè)單詞放進(jìn)哪個(gè)list,需要用if語句。
提示:當(dāng)一個(gè)元素特別長的時(shí)候,給代碼多加一個(gè)list。
提示:加個(gè)換行,優(yōu)化用戶視角。
新增一個(gè)list,用于統(tǒng)計(jì)用戶認(rèn)識(shí)的單詞。
創(chuàng)建一個(gè)空的列表,用于記錄用戶認(rèn)識(shí)的單詞。
創(chuàng)建一個(gè)空的列表,用于記錄用戶不認(rèn)識(shí)的單詞。
啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于單詞的數(shù)量。
如果用戶認(rèn)識(shí):就把這個(gè)單詞,追加進(jìn)列表words_knows。
否則,就把這個(gè)單詞,追加進(jìn)列表not_knows。
打印一個(gè)統(tǒng)計(jì)數(shù)據(jù):這么多單詞,認(rèn)識(shí)幾個(gè),認(rèn)識(shí)的有哪些?
【解答】
選擇語言
danci = []
#新增一個(gè)list,用于統(tǒng)計(jì)用戶認(rèn)識(shí)的單詞
words_knows = []
not_knows = []
print ('測(cè)試現(xiàn)在開始。如果你認(rèn)識(shí)這個(gè)單詞,請(qǐng)輸入Y,否則直接敲Enter:')
n=0
for x in words['data']:
n=n+1
print ('\n第'+str(n)+'個(gè):'+x['content'])
#加一個(gè)\n,用于換行。
answer = input('認(rèn)識(shí)請(qǐng)敲Y,否則敲Enter:')
if answer == 'Y':
danci.append(x['content'])
#把用戶認(rèn)識(shí)的單詞,追加進(jìn)danci這個(gè)list。
words_knows.append(x)
else:
not_knows.append(x)
print ('\n在上述'+str(len(words['data']))+'個(gè)單詞當(dāng)中,有'+str(len(danci))+'個(gè)是你覺得自己認(rèn)識(shí)的,它們是:')
print(danci)
(3). 對(duì)于用戶認(rèn)識(shí)的單詞,給選擇題讓用戶做:此處要記錄用戶做對(duì)了哪些,做錯(cuò)了哪些。
這一步是第0步和第2步的組合——涉及到第0步中的選擇,也涉及到第2步的數(shù)據(jù)記錄。
提示: 面對(duì)冗長的字典列表相互嵌套,可以創(chuàng)建字典。
【解答】
選擇語言
print ('現(xiàn)在我們來檢測(cè)一下,你有沒有真正掌握它們:')
wrong_words = []
right_num = 0
for y in words_knows:
print('\n\n'+'A:'+y['definition_choices'][0]['definition'])
#我們改用A、B、C、D,不再用rank值,下同
print('B:'+y['definition_choices'][1]['definition'])
print('C:'+y['definition_choices'][2]['definition'])
print('D:'+y['definition_choices'][3]['definition'])
xuanze = input('請(qǐng)選擇單詞\''+y['content']+'\'的正確翻譯:')
dic = {'A':y['definition_choices'][0]['rank'],'B':y['definition_choices'][1]['rank'],'C':y['definition_choices'][2]['rank'],'D':y['definition_choices'][3]['rank']}
#我們創(chuàng)建一個(gè)字典,搭建起A、B、C、D和四個(gè)rank值的映射關(guān)系。
if dic[xuanze] == y['rank']:
#此時(shí)dic[xuanze]的內(nèi)容,其實(shí)就是rank值,此時(shí)的代碼含義已經(jīng)和之前的版本相同了。
right_num += 1
else:
wrong_words.append(y)
(4). 生成報(bào)告:50個(gè)單詞,不認(rèn)識(shí)多少,認(rèn)識(shí)多少,掌握多少,錯(cuò)了多少。
生成報(bào)告主要有三部分:第0,是輸出統(tǒng)計(jì)數(shù)據(jù);第1,是打印錯(cuò)題集;第2,是把錯(cuò)題集保存到本地。
【解答】
選擇語言
import requests
link = requests.get('https://www.shanbay.com/api/v1/vocabtest/category/')
#先用requests下載鏈接。
js_link = link.json()
#解析下載得到的內(nèi)容。
bianhao = int(input('''請(qǐng)輸入你選擇的詞庫編號(hào),按Enter確認(rèn)
1,GMAT 2,考研 3,高考 4,四級(jí) 5,六級(jí)
6,英專 7,托福 8,GRE 9,雅思 10,任意
>'''))
#讓用戶選擇自己想測(cè)的詞庫,輸入數(shù)字編號(hào)。int()來轉(zhuǎn)換數(shù)據(jù)類型
ciku = js_link['data'][bianhao-1][0]
#利用用戶輸入的數(shù)字編號(hào),獲取題庫的代碼。如果以輸入“高考”的編號(hào)“3”為例,那么ciku的值就是,在字典js_link中查找data的值,data是一個(gè)list,查找它的第bianhao-1,也就是第2個(gè)元素,得到的依然是一個(gè)list,再查找該list的第0個(gè)元素。最后得到的就是我們想要的NCEE。
test = requests.get('https://www.shanbay.com/api/v1/vocabtest/vocabularies/?category='+ciku)
#下載用于測(cè)試的50個(gè)單詞。
words = test.json()
#對(duì)test進(jìn)行解析。
danci = []
#新增一個(gè)list,用于統(tǒng)計(jì)用戶認(rèn)識(shí)的單詞
words_knows = []
#創(chuàng)建一個(gè)空的列表,用于記錄用戶認(rèn)識(shí)的單詞。
not_knows = []
#創(chuàng)建一個(gè)空的列表,用于記錄用戶不認(rèn)識(shí)的單詞。
print ('測(cè)試現(xiàn)在開始。如果你認(rèn)識(shí)這個(gè)單詞,請(qǐng)輸入Y,否則直接敲Enter:')
n=0
for x in words['data']:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于單詞的數(shù)量。
n=n+1
print ('\n第'+str(n)+'個(gè):'+x['content'])
#加一個(gè)\n,用于換行。
answer = input('認(rèn)識(shí)請(qǐng)敲Y,否則敲Enter:')
#讓用戶輸入自己是否認(rèn)識(shí)。
if answer == 'Y':
#如果用戶認(rèn)識(shí):
danci.append(x['content'])
words_knows.append(x)
#就把這個(gè)單詞,追加進(jìn)列表words_knows。
else:
#否則
not_knows.append(x)
#就把這個(gè)單詞,追加進(jìn)列表not_knows。
print ('\n在上述'+str(len(words['data']))+'個(gè)單詞當(dāng)中,有'+str(len(danci))+'個(gè)是你覺得自己認(rèn)識(shí)的,它們是:')
print(danci)
print ('現(xiàn)在我們來檢測(cè)一下,你有沒有真正掌握它們:')
wrong_words = []
right_num = 0
for y in words_knows:
print('\n\n'+'A:'+y['definition_choices'][0]['definition'])
#我們改用A、B、C、D,不再用rank值,下同
print('B:'+y['definition_choices'][1]['definition'])
print('C:'+y['definition_choices'][2]['definition'])
print('D:'+y['definition_choices'][3]['definition'])
xuanze = input('請(qǐng)選擇單詞\''+y['content']+'\'的正確翻譯(填寫數(shù)字即可):')
dic = {'A':y['definition_choices'][0]['rank'],'B':y['definition_choices'][1]['rank'],'C':y['definition_choices'][2]['rank'],'D':y['definition_choices'][3]['rank']}
#我們創(chuàng)建一個(gè)字典,搭建起A、B、C、D和四個(gè)rank值的映射關(guān)系。
if dic[xuanze] == y['rank']:
#此時(shí)dic[xuanze]的內(nèi)容,其實(shí)就是rank值,此時(shí)的代碼含義已經(jīng)和之前的版本相同了。
right_num += 1
else:
wrong_words.append(y)
print ('現(xiàn)在,到了公布成績的時(shí)刻:')
print ('在'+str(len(words['data']))+'個(gè)'+js_link['data'][bianhao-1][1]+'詞匯當(dāng)中,你認(rèn)識(shí)其中'+str(len(danci))+'個(gè),實(shí)際掌握'+str(right_num)+'個(gè),錯(cuò)誤'+str(len(wrong_words))+'個(gè)。')
#這是句蠻復(fù)雜的話,對(duì)照前面的代碼和json文件你才能理解它。一個(gè)運(yùn)行示例是:在50個(gè)高考詞匯當(dāng)中,你認(rèn)識(shí)其中30個(gè),實(shí)際掌握25個(gè),錯(cuò)誤5個(gè)。
save = input ('是否打印并保存你的錯(cuò)詞集?填入Y或N: ')
#詢問用戶,是否要打印并保存錯(cuò)題集。
if save == 'Y':
#如果用戶說是:
f = open('錯(cuò)題集.txt', 'a+')
#在當(dāng)前目錄下,創(chuàng)建一個(gè)錯(cuò)題集.txt的文檔。
print ('你記錯(cuò)的單詞有:')
f.write('你記錯(cuò)的單詞有:\n')
#寫入'你記錯(cuò)的單詞有:\n'
m=0
for z in wrong_words:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于,用戶的錯(cuò)詞數(shù):
m=m+1
print (z['content'])
#打印每一個(gè)錯(cuò)詞。
f.write(str(m+1) +'. '+ z['content']+'\n')
#寫入序號(hào),寫入錯(cuò)詞。
print ('你不認(rèn)識(shí)的單詞有:')
f.write('你沒記住的單詞有:\n')
#寫入'你沒記住的單詞有:\n'
s=0
for x in not_knows:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于,用戶不認(rèn)識(shí)的單詞數(shù)。
print (x['content'])
#打印每一個(gè)不認(rèn)識(shí)的單詞。
f.write(str(s+1) +'. '+ x['content']+'\n')
#寫入序號(hào),寫入用戶不認(rèn)識(shí)的詞匯。
print ('錯(cuò)詞和沒記住的詞已保存至當(dāng)前文件目錄下,下次見!')
#告訴用戶,文件已經(jīng)保存好。
#在網(wǎng)頁版終端運(yùn)行時(shí),文件會(huì)被寫在課程的服務(wù)器上,你看不到,但它的確已經(jīng)存在。
else:
#如果用戶不想保存:
print('下次見!')
#輸出“下次見!”
三步:參考答案
參考答案:
選擇語言
import requests
link = requests.get('https://www.shanbay.com/api/v1/vocabtest/category/')
#先用requests下載鏈接。
js_link = link.json()
#解析下載得到的內(nèi)容。
bianhao = int(input('''請(qǐng)輸入你選擇的詞庫編號(hào),按Enter確認(rèn)
1,GMAT 2,考研 3,高考 4,四級(jí) 5,六級(jí)
6,英專 7,托福 8,GRE 9,雅思 10,任意
>'''))
#讓用戶選擇自己想測(cè)的詞庫,輸入數(shù)字編號(hào)。int()來轉(zhuǎn)換數(shù)據(jù)類型
ciku = js_link['data'][bianhao-1][0]
#利用用戶輸入的數(shù)字編號(hào),獲取題庫的代碼。如果以輸入“高考”的編號(hào)“3”為例,那么ciku的值就是,在字典js_link中查找data的值,data是一個(gè)list,查找它的第bianhao-1,也就是第2個(gè)元素,得到的依然是一個(gè)list,再查找該list的第0個(gè)元素。最后得到的就是我們想要的NCEE。
test = requests.get('https://www.shanbay.com/api/v1/vocabtest/vocabularies/?category='+ciku)
#下載用于測(cè)試的50個(gè)單詞。
words = test.json()
#對(duì)test進(jìn)行解析。
danci = []
#新增一個(gè)list,用于統(tǒng)計(jì)用戶認(rèn)識(shí)的單詞
words_knows = []
#創(chuàng)建一個(gè)空的列表,用于記錄用戶認(rèn)識(shí)的單詞。
not_knows = []
#創(chuàng)建一個(gè)空的列表,用于記錄用戶不認(rèn)識(shí)的單詞。
print ('測(cè)試現(xiàn)在開始。如果你認(rèn)識(shí)這個(gè)單詞,請(qǐng)輸入Y,否則直接敲Enter:')
n=0
for x in words['data']:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于單詞的數(shù)量。
n=n+1
print ('\n第'+str(n)+'個(gè):'+x['content'])
#加一個(gè)\n,用于換行。
answer = input('認(rèn)識(shí)請(qǐng)敲Y,否則敲Enter:')
#讓用戶輸入自己是否認(rèn)識(shí)。
if answer == 'Y':
#如果用戶認(rèn)識(shí):
danci.append(x['content'])
words_knows.append(x)
#就把這個(gè)單詞,追加進(jìn)列表words_knows。
else:
#否則
not_knows.append(x)
#就把這個(gè)單詞,追加進(jìn)列表not_knows。
print ('\n在上述'+str(len(words['data']))+'個(gè)單詞當(dāng)中,有'+str(len(danci))+'個(gè)是你覺得自己認(rèn)識(shí)的,它們是:')
print(danci)
print ('現(xiàn)在我們來檢測(cè)一下,你有沒有真正掌握它們:')
wrong_words = []
right_num = 0
for y in words_knows:
print('\n\n'+'A:'+y['definition_choices'][0]['definition'])
#我們改用A、B、C、D,不再用rank值,下同
print('B:'+y['definition_choices'][1]['definition'])
print('C:'+y['definition_choices'][2]['definition'])
print('D:'+y['definition_choices'][3]['definition'])
xuanze = input('請(qǐng)選擇單詞\''+y['content']+'\'的正確翻譯(填寫數(shù)字即可):')
dic = {'A':y['definition_choices'][0]['rank'],'B':y['definition_choices'][1]['rank'],'C':y['definition_choices'][2]['rank'],'D':y['definition_choices'][3]['rank']}
#我們創(chuàng)建一個(gè)字典,搭建起A、B、C、D和四個(gè)rank值的映射關(guān)系。
if dic[xuanze] == y['rank']:
#此時(shí)dic[xuanze]的內(nèi)容,其實(shí)就是rank值,此時(shí)的代碼含義已經(jīng)和之前的版本相同了。
right_num += 1
else:
wrong_words.append(y)
print ('現(xiàn)在,到了公布成績的時(shí)刻:')
print ('在'+str(len(words['data']))+'個(gè)'+js_link['data'][bianhao-1][1]+'詞匯當(dāng)中,你認(rèn)識(shí)其中'+str(len(danci))+'個(gè),實(shí)際掌握'+str(right_num)+'個(gè),錯(cuò)誤'+str(len(wrong_words))+'個(gè)。')
#這是句蠻復(fù)雜的話,對(duì)照前面的代碼和json文件你才能理解它。一個(gè)運(yùn)行示例是:在50個(gè)高考詞匯當(dāng)中,你認(rèn)識(shí)其中30個(gè),實(shí)際掌握25個(gè),錯(cuò)誤5個(gè)。
save = input ('是否打印并保存你的錯(cuò)詞集?填入Y或N: ')
#詢問用戶,是否要打印并保存錯(cuò)題集。
if save == 'Y':
#如果用戶說是:
f = open('錯(cuò)題集.txt', 'a+')
#在當(dāng)前目錄下,創(chuàng)建一個(gè)錯(cuò)題集.txt的文檔。
print ('你記錯(cuò)的單詞有:')
f.write('你記錯(cuò)的單詞有:\n')
#寫入'你記錯(cuò)的單詞有:\n'
m=0
for z in wrong_words:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于,用戶的錯(cuò)詞數(shù):
m=m+1
print (z['content'])
#打印每一個(gè)錯(cuò)詞。
f.write(str(m+1) +'. '+ z['content']+'\n')
#寫入序號(hào),寫入錯(cuò)詞。
print ('你不認(rèn)識(shí)的單詞有:')
f.write('你沒記住的單詞有:\n')
#寫入'你沒記住的單詞有:\n'
s=0
for x in not_knows:
#啟動(dòng)一個(gè)循環(huán),循環(huán)的次數(shù)等于,用戶不認(rèn)識(shí)的單詞數(shù)。
print (x['content'])
#打印每一個(gè)不認(rèn)識(shí)的單詞。
f.write(str(s+1) +'. '+ x['content']+'\n')
#寫入序號(hào),寫入用戶不認(rèn)識(shí)的詞匯。
print ('錯(cuò)詞和沒記住的詞已保存至當(dāng)前文件目錄下,下次見!')
#告訴用戶,文件已經(jīng)保存好。
#在網(wǎng)頁版終端運(yùn)行時(shí),文件會(huì)被寫在課程的服務(wù)器上,你看不到,但它的確已經(jīng)存在。
else:
#如果用戶不想保存:
print('下次見!')
#輸出“下次見!
第8關(guān)
練習(xí)-我家附近有啥好吃的-參考
項(xiàng)目目標(biāo):在本練習(xí),我們會(huì)借助cookies的相關(guān)知識(shí),使用Python登錄餓了么網(wǎng)站,爬取自己家附近的餐廳列表。
網(wǎng)站地址:https://www.ele.me/home/
【講解】
在本練習(xí),我們會(huì)借助cookies的相關(guān)知識(shí),使用Python登錄餓了么網(wǎng)站,爬取自己家附近的餐廳。
網(wǎng)站地址:https://www.ele.me/home/
想要順利地爬取餓了么上面的餐廳列表,我們需要先自己前往餓了么網(wǎng)站,手動(dòng)找到餐廳列表所在位置。然后,再用Python代碼去模擬這個(gè)過程。
首先,打開餓了么首頁:(https://www.ele.me/home/)
打開【檢查】工具,選擇【Network】,勾選【Preserve log】(因?yàn)榈葧?huì)可能會(huì)有頁面跳轉(zhuǎn),勾選上防止在跳轉(zhuǎn)過程中請(qǐng)求被清空)。
??
然后,輸入地址,如:“騰訊大廈”(推薦先把文字打好,再利用復(fù)制粘貼一次性輸入,不要一個(gè)字一個(gè)字填輸),頁面會(huì)彈出許多個(gè)地址給你選擇。此刻,會(huì)看到右側(cè)的Network面板里多出一個(gè)XHR:pois?……
這說明,這些地址列表和XHR之間存在有對(duì)應(yīng)關(guān)系。記住這個(gè)XHR,它很重要,后面會(huì)用到。
我們先點(diǎn)擊一個(gè)地址,比如我選擇的第0個(gè),“騰訊大廈”,它會(huì)跳轉(zhuǎn)至一個(gè)新地址:(https://www.ele.me/place/ws100xkkpznf?latitude=22.54055&longitude=113.934401)
??
此時(shí),頁面要求我們登錄。我們點(diǎn)擊登錄,會(huì)來到(https://h5.ele.me/login/#redirect=https%3A%2F%2Fwww.ele.me%2Fplace%2Fws100xkkpznf%3Flatitude%3D22.54055%26longitude%3D113.934401)
??
閱讀該URL,很容易能夠看出這個(gè)是一個(gè)登錄頁,因?yàn)橛衛(wèi)ogin存在。同時(shí)它在?之后所攜帶的參數(shù),含義是來源:我們剛剛從哪個(gè)URL跳轉(zhuǎn)過來。
輸入手機(jī)號(hào)碼,點(diǎn)擊收取驗(yàn)證碼,此時(shí)瀏覽器會(huì)發(fā)起請(qǐng)求:mobile_send_code。
手機(jī)收到驗(yàn)證碼,輸入驗(yàn)證碼,完成登錄。頁面會(huì)重新跳轉(zhuǎn)回我們剛剛來到的地址,此時(shí)的頁面,出現(xiàn)了我們想要的餐館名。
??
login_by_mobile即是登錄獲取cookies的那個(gè)請(qǐng)求。
通過翻找Network,我們定位到,存儲(chǔ)有餐廳列表的請(qǐng)求是XHR:restaurants…
該請(qǐng)求需要若干參數(shù),如下:
1. extras[]:activities
2. geohash:通過搜索得之,這是一個(gè)能夠代表地理位置的字符串。
3. latitude:緯度
4. limit:一次加載多少個(gè)餐館
5. longitude:經(jīng)度
6. offset:起始值
7. terminal: web
思考實(shí)現(xiàn)方案
這個(gè)網(wǎng)站,要求登錄才能實(shí)現(xiàn)爬取餐館列表。所以我們需要用到cookies來實(shí)現(xiàn)。
所以理論上,我們的代碼順序應(yīng)該是:模擬登錄獲取cookies,再帶著cookies去請(qǐng)求餐館列表。
不過,必須要指出的是。請(qǐng)求餐館列表,還需要一些參數(shù)才行。這些參數(shù),和我們剛剛在首頁輸入“騰訊大廈”四個(gè)字的操作有關(guān)。
具體,我們?cè)谧龃a實(shí)操時(shí)再展開講解。
所以正確的過程應(yīng)該是:
- 模擬登錄獲取cookies
- 模擬輸入“騰訊大廈”獲取必要的參數(shù)
- 帶著參數(shù)和cookies,去請(qǐng)求餐館列表
其中,前兩步可以順序調(diào)換。
【講解】
下面,我將帶你一步步完成代碼。
一、使用session和cookies模擬登錄
體驗(yàn)登錄:https://h5.ele.me/login/
提示:此處需要先模擬發(fā)送驗(yàn)證碼的請(qǐng)求,再模擬登錄的請(qǐng)求。
提示:請(qǐng)求驗(yàn)證碼時(shí),會(huì)返回一個(gè)json,json里會(huì)有validate_token。它在我們輸入賬號(hào)驗(yàn)證碼模擬登錄的時(shí)候,會(huì)用到。
模擬登錄參考示例:
選擇語言
import requests
session = requests.session()
#創(chuàng)建會(huì)話。
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
#添加請(qǐng)求頭,避免被反爬蟲。
url = ' https://wordpress-edu-3autumn.localprod.forc.work/wp-login.php'
#登錄的網(wǎng)址。
data = {'log': input('請(qǐng)輸入你的賬號(hào):'),
'pwd': input('請(qǐng)輸入你的密碼:'),
'wp-submit': '登錄',
'redirect_to': 'https://wordpress-edu-3autumn.localprod.forc.work/wp-admin/',
'testcookie': '1'}
#登錄的參數(shù)。
session.post(url, headers=headers, data=data)
#在會(huì)話下,用post發(fā)起登錄請(qǐng)求。
【解答】
選擇語言
import requests
session = requests.session()
# 創(chuàng)建會(huì)話
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
# 添加請(qǐng)求頭,避免被反爬蟲
url_1 = 'https://h5.ele.me/restapi/eus/login/mobile_send_code'
# 發(fā)送驗(yàn)證碼的網(wǎng)址
tel = input('請(qǐng)輸入手機(jī)號(hào)碼:')
data_1 = {'captcha_hash':'',
'captcha_value':'',
'mobile':tel,
'scf':''}
# 發(fā)送驗(yàn)證碼的參數(shù)
token = session.post(url_1, headers=headers, data=data_1).json()['validate_token']
# 在會(huì)話下,模擬獲取驗(yàn)證碼的請(qǐng)求
url_2 = 'https://h5.ele.me/restapi/eus/login/login_by_mobile'
code = input('請(qǐng)輸入手機(jī)驗(yàn)證碼:')
data_2 = {'mobile':tel,
'scf':'ms',
'validate_code':code,
'validate_token':token}
session.post(url_2,headers=headers,data=data_2)
二、模擬輸入地址,獲取必要參數(shù)
為了請(qǐng)求餐館列表,我們需要幾個(gè)關(guān)鍵參數(shù):
1. geohash:通過搜索得之,這是一個(gè)能夠代表地理位置的字符串。
2. latitude:緯度
3. longitude:經(jīng)度
這三個(gè)參數(shù),都需要模擬輸入地址來獲得。請(qǐng)打印出這三個(gè)參數(shù)。
體驗(yàn)輸入地址:https://www.ele.me/home/
提示:本步驟不需要模擬登錄
提示:在模擬該請(qǐng)求時(shí)需要用到城市的geohash值,可在XHR里查看自己城市的geohash值
【解答】
選擇語言
import requests
# 導(dǎo)入requests模塊。
address_url = 'https://www.ele.me/restapi/v2/pois?'
# 你能夠在【Headers】-【General】里找到這個(gè)鏈接。
place = input('請(qǐng)輸入你的收貨地址:')
# 使用input輸入收獲地址,賦值給place。
# 因?yàn)槲覀兊膅eohash使用了深圳的值,所以推薦你測(cè)試的時(shí)候使用“騰訊大廈”。
params = {'extras[]':'count','geohash':'ws105rz9smwm','keyword':place,'limit':'20','type':'nearby'}
# 將要傳遞的參數(shù)封裝成字典,鍵與值都要用字符串,其中keyword對(duì)于的值是place。
address_res = requests.get(address_url,params=params)
# 發(fā)起請(qǐng)求,將響應(yīng)的結(jié)果,賦值給address_res
address_json = address_res.json()
# 將響應(yīng)的結(jié)果轉(zhuǎn)為列表/字典。
print('以下,是與'+place+'相關(guān)的位置信息:\n')
n=0
# 添加一個(gè)計(jì)數(shù)器,作為序號(hào)。
for address in address_json:
# 遍歷我們剛爬取的地址列表。
print(str(n)+'. '+address['name']+':'+address['short_address']+'\n')
# 打印序號(hào),地址名,短地址。
n = n+1
# 給計(jì)數(shù)器加1。
address_num = int(input('請(qǐng)輸入您選擇位置的序號(hào):'))
# 讓用戶選擇序號(hào)。
final_address = address_json[address_num]
# 確認(rèn)地址。
print(final_address['geohash'])
print(final_address['latitude'])
print(final_address['longitude'])
三、帶cookies和參數(shù)請(qǐng)求餐館列表
最后一步,將上述兩組代碼組合。
拿到cookies和參數(shù),完成請(qǐng)求餐館列表。
我?guī)湍泐A(yù)置了前兩個(gè)代碼,你可以在此基礎(chǔ)上完成本關(guān)卡任務(wù)。
【解答】
選擇語言
import requests
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
url_1 = 'https://h5.ele.me/restapi/eus/login/mobile_send_code'
tel = input('請(qǐng)輸入手機(jī)號(hào)碼:')
data_1 = {'captcha_hash':'',
'captcha_value':'',
'mobile':tel,
'scf':''}
token = session.post(url_1, headers=headers, data=data_1).json()['validate_token']
url_2 = 'https://h5.ele.me/restapi/eus/login/login_by_mobile'
code = input('請(qǐng)輸入手機(jī)驗(yàn)證碼:')
data_2 = {'mobile':tel,
'scf':'ms',
'validate_code':code,
'validate_token':token}
session.post(url_2,headers=headers,data=data_2)
address_url = 'https://www.ele.me/restapi/v2/pois?'
place = input('請(qǐng)輸入你的收貨地址:')
params = {'extras[]':'count','geohash':'ws105rz9smwm','keyword':place,'limit':'20','type':'nearby'}
# 這里使用了深圳的geohash
address_res = requests.get(address_url,params=params)
address_json = address_res.json()
print('以下,是與'+place+'相關(guān)的位置信息:\n')
n=0
for address in address_json:
print(str(n)+'. '+address['name']+':'+address['short_address']+'\n')
n = n+1
address_num = int(input('請(qǐng)輸入您選擇位置的序號(hào):'))
final_address = address_json[address_num]
restaurants_url = 'https://www.ele.me/restapi/shopping/restaurants?'
# 使用帶有餐館列表的那個(gè)XHR地址。
params = {'extras[]':'activities',
'geohash':final_address['geohash'],
'latitude':final_address['latitude'],
'limit':'24',
'longitude':final_address['longitude'],
'offset':'0',
'terminal':'web'
}
# 將參數(shù)封裝,其中g(shù)eohash和經(jīng)緯度,來自前面獲取到的數(shù)據(jù)。
restaurants_res = session.get(restaurants_url,params=params)
# 發(fā)起請(qǐng)求,將響應(yīng)的結(jié)果,賦值給restaurants_res
restaurants = restaurants_res.json()
# 把response對(duì)象,轉(zhuǎn)為json。
for restaurant in restaurants:
# restsurants最外層是一個(gè)列表,它可被遍歷。restaurant則是字典,里面包含了單個(gè)餐廳的所有信息。
print(restaurant['name'])
參考答案和總結(jié)
參考答案:
選擇語言
import requests
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
url_1 = 'https://h5.ele.me/restapi/eus/login/mobile_send_code'
tel = input('請(qǐng)輸入手機(jī)號(hào)碼:')
data_1 = {'captcha_hash':'',
'captcha_value':'',
'mobile':tel,
'scf':''}
token = session.post(url_1, headers=headers, data=data_1).json()['validate_token']
url_2 = 'https://h5.ele.me/restapi/eus/login/login_by_mobile'
code = input('請(qǐng)輸入手機(jī)驗(yàn)證碼:')
data_2 = {'mobile':tel,
'scf':'ms',
'validate_code':code,
'validate_token':token}
session.post(url_2,headers=headers,data=data_2)
address_url = 'https://www.ele.me/restapi/v2/pois?'
place = input('請(qǐng)輸入你的收貨地址:')
params = {'extras[]':'count','geohash':'ws105rz9smwm','keyword':place,'limit':'20','type':'nearby'}
# 這里使用了深圳的geohash
address_res = requests.get(address_url,params=params)
address_json = address_res.json()
print('以下,是與'+place+'相關(guān)的位置信息:\n')
n=0
for address in address_json:
print(str(n)+'. '+address['name']+':'+address['short_address']+'\n')
n = n+1
address_num = int(input('請(qǐng)輸入您選擇位置的序號(hào):'))
final_address = address_json[address_num]
restaurants_url = 'https://www.ele.me/restapi/shopping/restaurants?'
# 使用帶有餐館列表的那個(gè)XHR地址。
params = {'extras[]':'activities',
'geohash':final_address['geohash'],
'latitude':final_address['latitude'],
'limit':'24',
'longitude':final_address['longitude'],
'offset':'0',
'terminal':'web'
}
# 將參數(shù)封裝,其中g(shù)eohash和經(jīng)緯度,來自前面獲取到的數(shù)據(jù)。
restaurants_res = session.get(restaurants_url,params=params)
# 發(fā)起請(qǐng)求,將響應(yīng)的結(jié)果,賦值給restaurants_res
restaurants = restaurants_res.json()
# 把response對(duì)象,轉(zhuǎn)為json。
for restaurant in restaurants:
# restsurants最外層是一個(gè)列表,它可被遍歷。restaurant則是字典,里面包含了單個(gè)餐廳的所有信息。
print(restaurant['name'])
下面講一下會(huì)遇到的問題~
validate_token這個(gè)在哪里可以找到呢?
??
輸入手機(jī)號(hào)碼,點(diǎn)擊獲取 驗(yàn)證碼后,在文件mobile_send_code的Preview里面
??
出現(xiàn)這樣的錯(cuò)誤keyerror:validate_token
或者:{'message': '賬戶存在風(fēng)險(xiǎn),需要圖形驗(yàn)證碼', 'name': 'NEED_CAPTCHA'}
??
出現(xiàn)這個(gè)問題一般ip請(qǐng)求多次,一般第4次后,就可能引起餓了么的反爬機(jī)制,導(dǎo)致出現(xiàn)你的訪問異常,結(jié)果是keyerror錯(cuò)誤;也就是需要圖形驗(yàn)證碼;
在山腰的知識(shí)暫時(shí)是無法解決的,目前可以每天嘗試幾次,或者換個(gè)手機(jī)或者ip網(wǎng)絡(luò);例如熱點(diǎn);建議出現(xiàn)keyerror可以暫時(shí)運(yùn)行跳過,后續(xù)再試;一天一般有3-4次機(jī)會(huì)
如果要通過圖片驗(yàn)證,一般主流有4種方法:
1)打碼平臺(tái)付費(fèi)打碼
2)PIL庫提取圖片文字
3)第9關(guān)的selenium模擬
選擇語言
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'}
def get_picture():
url = 'https://h5.ele.me/restapi/eus/v3/captchas'
param = {'captcha_str':input('手機(jī)號(hào)碼')}
res = requests.get(url,params=param).json()['captcha_image']
import time
from selenium import webdriver
driver = webdriver.Chrome()
driver.get(res)
time.sleep(5)
4)get_picture()
找到圖片驗(yàn)證碼在network里的位置,像爬圖片一樣保存到本地,然后input模擬輸入驗(yàn)證碼
(*在網(wǎng)頁中輸入手機(jī)號(hào),需要輸入驗(yàn)證碼,在network里的img里找到驗(yàn)證碼所在的圖片,在像第0關(guān)教的爬取圖片一樣爬到本地展示,在模擬input輸入)
選擇語言
import requests
url = 'https://h5.ele.me/restapi/eus/v3/captchas'
headers = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'cookie': 'ubt_ssid=tita2xpcvoy6tbuzvwldp2tng4pz58l3_2019-04-28; _utrace=c2afcac7405b5632ba7a2987726b2cb4_2019-04-28; perf_ssid=e6xbec0ng906g0vof33vdf0vyrqgvts7_2019-04-28; UTUSER=0; cna=nawpFbIGrU8CAbcPsMlh4vqb; isg=BB0dLMZEHXmoNPlVLI0iBcyJLPkdMlOxf7IvI9_iInSjlj7Iq4jmXbNAwMo1VmlE',
}
captian = requests.get(url,headers=headers).json()
print(captian['captcha_image'])
補(bǔ)充:餓了么實(shí)現(xiàn)的參考博客
https://blog.csdn.net/weixin_43868179/article/details/94377658
餓了嗎里面那個(gè)查詢地址的鏈接是在哪找到的?
??
餓了么搜索地址的請(qǐng)求里url做了修改,練習(xí)時(shí)以網(wǎng)頁上實(shí)際的情況為準(zhǔn)
??
一份總結(jié):
就是這樣一個(gè)代碼,它能拿到給定位置附近的餐廳名。但它的潛力并不只是如此。
如果我們嘗試加載餓了么官網(wǎng)的首頁,能夠找到一個(gè)xhr叫做cities,這個(gè)xhr里包含了全國兩千多個(gè)城市的經(jīng)緯度。
利用Python的geohash模塊,你可以將經(jīng)緯度數(shù)據(jù),轉(zhuǎn)化為geohash(當(dāng)然,也可以將geohash轉(zhuǎn)為經(jīng)緯度,我也是用這種方式,發(fā)現(xiàn)我的默認(rèn)geohash是深圳)。
那么在理論上,其實(shí)你可以通過這種方式,拿到全國餐廳的數(shù)據(jù)……
只要稍做擴(kuò)展,它還能拿到許多數(shù)據(jù):所有的餐廳名/電話號(hào)碼/評(píng)分/品牌/經(jīng)緯度/介紹/均價(jià)/月銷量……
此時(shí),這個(gè)爬蟲就具備了商業(yè)價(jià)值,它能勝任許多數(shù)據(jù)分析的工作:選址策略、定價(jià)策略、差異化競(jìng)爭(zhēng)、2B營銷……
或許你會(huì)質(zhì)疑自己能不能做到像我描述的這樣厲害,不用怕,很快你就能夠做到對(duì)此心中有數(shù)。
而在后續(xù)的關(guān)卡,當(dāng)你學(xué)會(huì)反爬蟲的應(yīng)對(duì)策略、協(xié)程、Scrapy框架……你會(huì)變得像我說的那樣強(qiáng)大。
新練習(xí)-大神快更文
??
困難(#fb5a5c)
cookies與session post與get json數(shù)據(jù)解析與提取 反爬蟲應(yīng)對(duì)策略
要求:
在本練習(xí),我們會(huì)借助cookies的相關(guān)知識(shí),使用Python登錄小說網(wǎng)站,用代碼的形式對(duì)熱榜上的大神進(jìn)行催更。
網(wǎng)站地址:https://www.xslou.com/
目的:
- 練習(xí)掌握cookies和session的用法
- 練習(xí)post和get請(qǐng)求
- 練習(xí)json數(shù)據(jù)的解析提取
- 反爬蟲應(yīng)對(duì)策略
知識(shí)點(diǎn)回顧
cookies與session
cookies是服務(wù)器為了標(biāo)記用戶,存儲(chǔ)在用戶本地的數(shù)據(jù),它里面也保存了用戶的登錄信息,同時(shí)它有一定的時(shí)效性,過期就會(huì)失效。
??
session是會(huì)話過程中,服務(wù)器用來記錄特定用戶會(huì)話的信息。
??
session和cookies的關(guān)系:cookies里帶有session的編碼信息,服務(wù)器可以通過cookies辨別用戶,同時(shí)返回和這個(gè)用戶相關(guān)的特定編碼的session。
??
??
??
代碼示例如下:
選擇語言
import requests,json
session = requests.session()
#創(chuàng)建會(huì)話。
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
#添加請(qǐng)求頭,避免被反爬蟲。
try:
#如果能讀取到cookies文件,執(zhí)行以下代碼,跳過except的代碼,不用登錄就能發(fā)表評(píng)論。
cookies_txt = open('cookies.txt', 'r')
#以reader讀取模式,打開名為cookies.txt的文件。
cookies_dict = json.loads(cookies_txt.read())
#調(diào)用json模塊的loads函數(shù),把字符串轉(zhuǎn)成字典。
cookies = requests.utils.cookiejar_from_dict(cookies_dict)
#把轉(zhuǎn)成字典的cookies再轉(zhuǎn)成cookies本來的格式。
session.cookies = cookies
#獲取會(huì)話下的cookies
except FileNotFoundError:
#如果讀取不到cookies文件,程序報(bào)“FileNotFoundError”(找不到文件)的錯(cuò),則執(zhí)行以下代碼,重新登錄獲取cookies,再評(píng)論。
url = 'https://wordpress-edu-3autumn.localprod.oc.forchange.cn/wp-login.php'
#登錄的網(wǎng)址。
data = {'log': input('請(qǐng)輸入你的賬號(hào):'),
'pwd': input('請(qǐng)輸入你的密碼:'),
'wp-submit': '登錄',
'redirect_to': 'https://wordpress-edu-3autumn.localprod.forc.work/wp-admin/',
'testcookie': '1'}
#登錄的參數(shù)。
session.post(url, headers=headers, data=data)
#在會(huì)話下,用post發(fā)起登錄請(qǐng)求。
cookies_dict = requests.utils.dict_from_cookiejar(session.cookies)
#把cookies轉(zhuǎn)化成字典。
cookies_str = json.dumps(cookies_dict)
#調(diào)用json模塊的dump函數(shù),把cookies從字典再轉(zhuǎn)成字符串。
f = open('cookies.txt', 'w')
#創(chuàng)建名為cookies.txt的文件,以寫入模式寫入內(nèi)容
f.write(cookies_str)
#把已經(jīng)轉(zhuǎn)成字符串的cookies寫入文件
f.close()
#關(guān)閉文件
url_1 = 'https://wordpress-edu-3autumn.localprod.forc.work/wp-comments-post.php'
#文章的網(wǎng)址。
data_1 = {
'comment': input('請(qǐng)輸入你想評(píng)論的內(nèi)容:'),
'submit': '發(fā)表評(píng)論',
'comment_post_ID': '13',
'comment_parent': '0'
}
#評(píng)論的參數(shù)。
session.post(url_1, headers=headers, data=data_1)
#在會(huì)話下,用post發(fā)起評(píng)論請(qǐng)求。
post與get
post和get都可以帶著參數(shù)請(qǐng)求,不過get請(qǐng)求的參數(shù)會(huì)在url上顯示出來。但post請(qǐng)求的參數(shù)就不會(huì)直接顯示,而是隱藏起來。
在post請(qǐng)求里,我們使用data來傳遞參數(shù),其用法和params非常相像。
代碼示例:
選擇語言
import requests
url_1 = 'https://…'
headers = {'user-agent':''}
data = {}
# 定義url,headers和data
login_in = requests.post(url,headers=headers,data=data)
cookies = login_in.cookies
# 完成登錄,獲取cookies
url_2 = 'https://…'
params = {}
# 定義url和params
response = requests.get(url,headers=headers,params=params,cookies=cookies)
# 帶著cookies重新發(fā)起請(qǐng)求
步驟
題目要求
項(xiàng)目目標(biāo):在本練習(xí),我們會(huì)借助cookies的相關(guān)知識(shí),使用Python登錄小說樓,爬取熱榜小說,對(duì)作者進(jìn)行催更。
網(wǎng)站地址:https://www.xslou.com/
【講解】
在本練習(xí),我們會(huì)借助cookies的相關(guān)知識(shí),使用Python登錄小說樓,爬取熱榜小說,對(duì)作者進(jìn)行催更。
網(wǎng)站地址:https://www.xslou.com/
分步講解
在這一步,我會(huì)帶領(lǐng)你完成“分析過程”,請(qǐng)務(wù)必完整閱讀文檔。
在下一步,我們會(huì)開始按步驟書寫代碼。
【講解】
體驗(yàn)流程
想要對(duì)熱榜的小說進(jìn)行催更,我們首先需要用瀏覽器體驗(yàn)這個(gè)過程。
前往小說樓,手動(dòng)找到熱榜所在位置
- 隨機(jī)對(duì)一部小說進(jìn)行催更
- 最后,再用Python代碼去模擬這個(gè)過程
進(jìn)入熱榜
首先,打開小說樓的排行榜頁:https://www.xslou.com/top/allvisit_1/
打開【檢查】工具,選擇【Network】,勾選【Preserve log】(因?yàn)榈葧?huì)可能會(huì)有頁面跳轉(zhuǎn),勾選上防止在跳轉(zhuǎn)過程中請(qǐng)求被清空)。 { 【新增圖片】
【原圖鏈接:】??
【原來的樣式:】??
【0】鼠標(biāo)右鍵選中下拉菜單的“檢查” 【1】選擇Network 【2】勾選Preserve log
??
體驗(yàn)登錄
1、然后我們可以隨機(jī)點(diǎn)擊其中一本小說,對(duì)其進(jìn)行催更 (現(xiàn)在網(wǎng)頁更新,已經(jīng)沒有催更功能了!建議同學(xué)們直接用下載小說來做練習(xí))
??
??
2、此時(shí),如果沒有登錄小說樓(或注冊(cè))的用戶,會(huì)自動(dòng)跳到小說樓的登錄頁面:https://www.xslou.com/login.php
也就是說,想要催更,我們必須通過登錄呀~(模擬登陸!?。〈吒牟襟E先不做?。?/span>
??
3、閱讀該URL,很容易能夠看出這個(gè)是一個(gè)登錄頁,因?yàn)橛墟溄佑袀€(gè)login(中文:登錄)
4、輸入賬號(hào)和密碼,同時(shí)查看Network,便會(huì)發(fā)現(xiàn)瀏覽器會(huì)攜帶著賬號(hào)和密碼發(fā)起Post請(qǐng)求。 { 【新增圖片】
【原圖鏈接:】??
??
獲取催更鏈接(換成下載小說鏈接)
1、完成登錄之后,頁面會(huì)跳轉(zhuǎn)到催更的頁面,提示催更成功 ??
通過翻找Network,我們定位到,催更的請(qǐng)求是就是當(dāng)前的url:https://www.xslou.com/modules/article/usercui.php?id=xxx { 【新增圖片】
【原圖鏈接:】??
} ??
該請(qǐng)求只需要一個(gè)參數(shù):id(書籍的id)
注意:該鏈接限制了每天催更不能超過5次,也就是說該鏈接的請(qǐng)求不能超過5次
獲取書籍id
1、進(jìn)入小說熱門列表頁面:https://www.xslou.com/top/allvisit_1/右鍵檢查, 發(fā)現(xiàn)該頁面的數(shù)據(jù)就在第0個(gè)請(qǐng)求當(dāng)中。
2、模擬催更書籍《純陽武神》時(shí),拿到的id是9356, 不過這個(gè)id到底從哪里來的? 要么,它藏在了HTML網(wǎng)頁當(dāng)中; 要么,它就是在請(qǐng)求的時(shí)候,后臺(tái)下發(fā)的。 可先在Elements搜索一下該id,看它在不在HTML里。 (【搜索快捷鍵】win:ctrl+f | mac:command+f) { 【新增圖片】
【原圖鏈接:】??} ??
3、經(jīng)過分析,發(fā)現(xiàn)id確實(shí)藏在了HTML頁面的鏈接當(dāng)中:https://www.xslou.com/yuedu/9356/
4、下一步就是將數(shù)字9356從鏈接中分離出來,方法有很多,老師這里只講解過濾器fliter過濾數(shù)字
選擇語言
link = 'https://www.xslou.com/yuedu/9356/'
# 字符串link過濾出數(shù)字id(9356)
id_list = list(filter(str.isdigit,link))
book_id = ''.join(book_id)
# 步驟解析:1、filter()過濾數(shù)字 2、filter對(duì)象轉(zhuǎn)列表 3、列表轉(zhuǎn)字符串
# filter(str.isdigit,字符串)
# 第一個(gè)參數(shù)用來判斷字符串的單個(gè)元素是否是數(shù)字,數(shù)字保留
# filter()返回的是對(duì)象,需要用list()函數(shù)轉(zhuǎn)換成列表
# ''.join(列表)將列表轉(zhuǎn)換成字符串
思考實(shí)現(xiàn)方案
所以正確的流程應(yīng)該是:
- 使用id參數(shù)和cookies請(qǐng)求催更
注:其中,前兩步可以順序調(diào)換。
代碼實(shí)現(xiàn)
【講解】
下面,我將帶你一步步完成代碼。
一、使用session和cookies模擬登錄
體驗(yàn)登錄:https://www.xslou.com/login.php
模擬登錄參考示例:
選擇語言
import requests
# 創(chuàng)建會(huì)話。
session = requests.session()
# 添加請(qǐng)求頭,避免被反爬蟲。
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
# 登錄的網(wǎng)址。
url = ' https://wordpress-edu-3autumn.localprod.oc.forchange.cn/wp-login.php'
# 登錄的參數(shù)。
data = {'log': input('請(qǐng)輸入你的賬號(hào):'),
'pwd': input('請(qǐng)輸入你的密碼:'),
'wp-submit': '登錄',
'redirect_to': 'https://wordpress-edu-3autumn.localprod.forc.work/wp-admin/',
'testcookie': '1'}
#在會(huì)話下,用post發(fā)起登錄請(qǐng)求。
session.post(url, headers=headers, data=data)
【代碼題】
【預(yù)設(shè)代碼】
# 小說樓登錄請(qǐng)求:https://www.xslou.com/login.php
【解答】
選擇語言
import requests
# 創(chuàng)建會(huì)話
session = requests.session()
# 偽裝請(qǐng)求頭
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
# 登錄url
login_url = 'https://www.xslou.com/login.php'
# 登錄的參數(shù)。
data = {'username':input('請(qǐng)輸入你的賬號(hào):'),
'password':input('請(qǐng)輸入你的密碼:'),
'action':'login'}
result = session.post(login_url, headers=headers, data=data)
二、獲取書籍id
想要請(qǐng)求催更XHR,我們需要拿到參數(shù)id,也就是書籍id
小說排行榜:https://www.xslou.com/top/allvisit_1/
提示1: 1. 本步驟不需要模擬登錄 2. 網(wǎng)站的編碼模式是gbk
提示2:
選擇語言
link = 'https://www.xslou.com/yuedu/9356/'
# 字符串link過濾出數(shù)字id(9356)
id_list = list(filter(str.isdigit,link))
book_id = ''.join(book_id)
# 步驟解析:1、filter()過濾數(shù)字 2、filter對(duì)象轉(zhuǎn)列表 3、列表轉(zhuǎn)字符串
# filter(str.isdigit,字符串)
# 第一個(gè)參數(shù)用來判斷字符串的單個(gè)元素是否是數(shù)字,數(shù)字保留
# filter()返回的是對(duì)象,需要用list()函數(shù)轉(zhuǎn)換成列表
# ''.join(列表)將列表轉(zhuǎn)換成字符串
提示3:
選擇語言
# 爬取鏈接html頁面中a標(biāo)簽的鏈接以及內(nèi)容
import requests
from bs4 import BeautifulSoup
url = 'https://movie.douban.com/top250?start=25&filter='
results = requests.get(url)
results.encoding = 'utf8'
bs = BeautifulSoup(results.text,'html.parser')
ols = bs.find('ol',class_='grid_view')
for ls in ols.find_all('li'):
url_movie = ls.find('a')['href']
url_text = ls.find('a').text
【代碼題】
【預(yù)設(shè)代碼】
# 本步驟不需要模擬登錄
# 小說樓的排行榜:https://www.xslou.com/top/allvisit_1/
【解答】
選擇語言
import requests
from bs4 import BeautifulSoup
hot_url = 'https://www.xslou.com/top/allvisit_1/'
r = requests.get(hot_url)
r.encoding = 'gbk'
bs = BeautifulSoup(r.text,'html.parser')
uls = bs.find_all('span',class_='up2')
books = {}
for li in uls:
book_name = li.find('a').text
link = li.find('a')['href']
id_list = list(filter(str.isdigit,link))
book_id = ''.join(id_list)
books[book_id] = book_name
print(books)
三、帶cookies和參數(shù)請(qǐng)求催更鏈接
將上述兩組代碼組合。
拿到cookies和參數(shù),完成催更請(qǐng)求(不要超過5次)
我?guī)湍泐A(yù)置了前兩個(gè)代碼,你可以在此基礎(chǔ)上完成本關(guān)卡任務(wù)。
注意: 1. 請(qǐng)求url需要拼接書籍id 2. 請(qǐng)求時(shí)候別忘了添加請(qǐng)求頭和cookies:cookies=session.cookies
【代碼題】
【預(yù)設(shè)代碼】
選擇語言
# 將上述兩組代碼組合。拿到cookies和參數(shù),完成催更請(qǐng)求。
# 我?guī)湍泐A(yù)置了前兩個(gè)代碼,你可以在此基礎(chǔ)上完成本關(guān)卡任務(wù)。
# 小說樓:https://www.xslou.com/
# 小說樓登錄:https://www.xslou.com/login.php
# 小說樓的排行榜:https://www.xslou.com/top/allvisit_1/
# 小說樓催更:https://www.xslou.com/modules/article/usercui.php?id=
import requests
from bs4 import BeautifulSoup
login_url = 'https://www.xslou.com/login.php'
hot_url = 'https://www.xslou.com/top/allvisit_1/'
urge_url = 'https://www.xslou.com/modules/article/usercui.php?id='
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
def login_cookies():
data = {'username':input('請(qǐng)輸入你的賬號(hào):'),
'password':input('請(qǐng)輸入你的密碼:'),
'action':'login'}
result = session.post(login_url, headers=headers, data=data)
def get_bookids():
result = requests.get(hot_url, headers=headers)
result.encoding = 'gbk'
bs = BeautifulSoup(result.text,'html.parser')
uls = bs.find_all('span',class_='up2')
books = {}
for li in uls:
book_name = li.find('a').text
link = li.find('a')['href']
id_list = list(filter(str.isdigit,link))
book_id = ''.join(id_list)
books[book_id] = book_name
return books
def urge(book_id):
# 請(qǐng)求催更鏈接需要拼接book_id
# 請(qǐng)求需要帶上headers和cookies
def main ():
login_cookies()
books = get_bookids()
print('--------熱門書籍--------')
for k,v in books.items():
print(k,':',v)
book_id = input('請(qǐng)輸入想要催更的書籍id:')
urge(book_id)
main()
【解答】
選擇語言
import requests
from bs4 import BeautifulSoup
login_url = 'https://www.xslou.com/login.php'
hot_url = 'https://www.xslou.com/top/allvisit_1/'
urge_url = 'https://www.xslou.com/modules/article/usercui.php?id='
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
def login_cookies():
data = {'username':input('請(qǐng)輸入你的賬號(hào):'),
'password':input('請(qǐng)輸入你的密碼:'),
'action':'login'}
result = session.post(login_url, headers=headers, data=data)
def get_bookids():
result = requests.get(hot_url, headers=headers)
result.encoding = 'gbk'
bs = BeautifulSoup(result.text,'html.parser')
uls = bs.find_all('span',class_='up2')
books = {}
for li in uls:
book_name = li.find('a').text
link = li.find('a')['href']
id_list = list(filter(str.isdigit,link))
book_id = ''.join(id_list)
books[book_id] = book_name
return books
def urge(book_id):
url = urge_url+book_id
result = session.get(url, headers=headers, cookies=session.cookies)
result.encoding = 'gbk'
if result.status_code == 200:
bs = BeautifulSoup(result.text,'html.parser')
urge_info = bs.find('div',class_='blocktitle').get_text()
urge_info2 = bs.find('div',class_='blockcontent').get_text()
print(urge_info)
print(urge_info2)
def main ():
login_cookies()
books = get_bookids()
print('--------熱門書籍--------')
for k,v in books.items():
print(k,':',v)
book_id = input('請(qǐng)輸入想要催更的書籍id:')
urge(book_id)
main()
參考答案和總結(jié)
【講解】
參考答案:
選擇語言
# 小說樓:https://www.xslou.com/
# 小說樓登錄:https://www.xslou.com/login.php
# 小說樓的排行榜:https://www.xslou.com/top/allvisit_1/
# 小說樓催更:https://www.xslou.com/modules/article/usercui.php?id=
import requests
from bs4 import BeautifulSoup
login_url = 'https://www.xslou.com/login.php'
hot_url = 'https://www.xslou.com/top/allvisit_1/'
urge_url = 'https://www.xslou.com/modules/article/usercui.php?id='
session = requests.session()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
}
def login_cookies():
data = {'username':input('請(qǐng)輸入你的賬號(hào):'),
'password':input('請(qǐng)輸入你的密碼:'),
'action':'login'}
result = session.post(login_url, headers=headers, data=data)
def get_bookids():
result = requests.get(hot_url, headers=headers)
result.encoding = 'gbk'
bs = BeautifulSoup(result.text,'html.parser')
uls = bs.find_all('span',class_='up2')
books = {}
for li in uls:
book_name = li.find('a').text
link = li.find('a')['href']
id_list = list(filter(str.isdigit,link))
book_id = ''.join(id_list)
books[book_id] = book_name
return books
def urge(book_id):
url = urge_url+book_id
result = session.get(url, headers=headers, cookies=session.cookies)
result.encoding = 'gbk'
if result.status_code == 200:
bs = BeautifulSoup(result.text,'html.parser')
urge_info = bs.find('div',class_='blocktitle').get_text()
urge_info2 = bs.find('div',class_='blockcontent').get_text()
print(urge_info)
print(urge_info2)
def main ():
login_cookies()
books = get_bookids()
print('--------熱門書籍--------')
for k,v in books.items():
print(k,':',v)
book_id = input('請(qǐng)輸入想要催更的書籍id:')
urge(book_id)
main()
練習(xí)-自制翻譯器-參考
第一步:分析問題,明確目標(biāo)
實(shí)現(xiàn)功能:用戶輸入英文或中文,程序即可打印出來對(duì)應(yīng)的譯文。
【講解】
我們?cè)谧筮呡斎胛淖?,那么瀏覽器會(huì)把輸入的信息傳輸給服務(wù)器,再返回對(duì)應(yīng)的內(nèi)容。
我們希望達(dá)成的效果如下圖,即用戶輸入英文或中文,程序即可打印出來對(duì)應(yīng)的譯文:
第二步:思考要用到的知識(shí)
【講解】
實(shí)現(xiàn)一鍵翻譯的功能,最簡(jiǎn)單的方案便是爬蟲。在此,我們選擇的網(wǎng)站是有道翻譯。
你在左邊輸入文字,那么瀏覽器會(huì)把你輸入的信息傳輸給服務(wù)器。再返回對(duì)應(yīng)的內(nèi)容。
??
??
這就是一個(gè)典型的Post操作。
我們?cè)贖eaders也可以看到“Request Method: POST”哦~
??
在前幾關(guān)練習(xí)我們用的都是Get方式請(qǐng)求,Post是另一種常見的方式,課上已經(jīng)學(xué)過其用法,在此不多贅述。
__Get是向服務(wù)器發(fā)索取數(shù)據(jù)的一種請(qǐng)求,而Post是向服務(wù)器提交數(shù)據(jù)的一種請(qǐng)求__
雖然第八關(guān)我們主要講的是Cookies~
__Cookies用于服務(wù)器實(shí)現(xiàn)會(huì)話,用戶登錄及相關(guān)功能時(shí)進(jìn)行狀態(tài)管理__
但這道題并不需要用到小餅干,因?yàn)椴恍枰卿洸恍枰~號(hào)密碼等。
主要考查的還是Post的用法。
__注意哦__ ?(????)
有道翻譯有反爬蟲機(jī)制,它使用了加密技術(shù)。如果你的程序報(bào)錯(cuò),你可以通過搜索、查閱資料找到解決方案:嘗試把訪問的網(wǎng)址中“/translate_o”中的“_o”刪除。
服務(wù)器返回的內(nèi)容,是json的格式。我們可以用處理列表、處理字典的手段來提取翻譯。
第三步:寫代碼
你可以在瀏覽器的[network]-[Headers]-[General]里找到需要訪問的網(wǎng)址,在[network]-[Headers]-[From data]里找到需要上傳的數(shù)據(jù)。
__再次注意哦__ ?(????)
有道翻譯有反爬蟲機(jī)制,它使用了加密技術(shù)。如果你的程序報(bào)錯(cuò),你可以通過搜索、查閱資料找到解決方案:嘗試把訪問的網(wǎng)址中“/translate_o”中的“_o”刪除。
服務(wù)器返回的內(nèi)容,是json的格式。我們可以用處理列表、處理字典的手段來提取翻譯。
【解答】
選擇語言
import requests,json
#調(diào)用了兩個(gè)模塊。requests負(fù)責(zé)上傳和下載數(shù)據(jù),json負(fù)責(zé)解析。
word = input('你想翻譯什么呀?')
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
#使用post需要一個(gè)鏈接。
data={'i': word,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTIME',
'typoResult': 'false'}
#將需要post的內(nèi)容,以字典的形式記錄在data內(nèi)。
r = requests.post(url,data)
#post需要輸入兩個(gè)參數(shù),一個(gè)是剛才的鏈接,一個(gè)是data,返回的是一個(gè)Response對(duì)象。
answer=json.loads(r.text)
#你可以自己嘗試print一下r.text的內(nèi)容,然后再閱讀下面的代碼。
print ('翻譯的結(jié)果是:'+answer['translateResult'][0][0]['tgt'])
第四步:套層殼(小彩蛋,了解即可,感興趣的話可以深入學(xué)習(xí))
我們總會(huì)聽到前端后端全棧,感覺神秘有高大上,你一定很好奇它們都是什么呀?
今天呢,我們就簡(jiǎn)單接觸下前端~
有米有很期待呀(?>???<‵)??
前端,是一種GUI軟件。而我們現(xiàn)在要用的是Python里的一個(gè)模塊實(shí)現(xiàn)本地窗口的功能。
它就是Tkinter~
Tkinter 模塊是 Python 的標(biāo)準(zhǔn) Tk GUI 工具包的接口。
Tk 和 Tkinter 可以在大多數(shù)的 Unix 平臺(tái)下使用,同樣可以應(yīng)用在 Windows 和 MacOS系統(tǒng)里。
Tk8.0 的后續(xù)版本可以實(shí)現(xiàn)本地窗口風(fēng)格,并良好地運(yùn)行在絕大多數(shù)平臺(tái)中。
http://www.runoob.com/python/python-gui-tkinter.html
最后的代碼大約是這個(gè)模樣,注意閱讀注釋~
當(dāng)然你可以在終端運(yùn)行(復(fù)制)這些代碼,觀察效果~
【解答】
認(rèn)真閱讀注釋,你也可以復(fù)制下來在你的IDE中運(yùn)行下哦~
選擇語言
import requests
import json
from tkinter import Tk,Button,Entry,Label,Text,END
class YouDaoFanyi(object):
def __init__(self):
pass
def crawl(self,word):
url='http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
#使用post需要一個(gè)鏈接
data={'i': word,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTIME',
'typoResult': 'false'}
#將需要post的內(nèi)容,以字典的形式記錄在data內(nèi)。
r = requests.post(url, data)
#post需要輸入兩個(gè)參數(shù),一個(gè)是剛才的鏈接,一個(gè)是data,返回的是一個(gè)Response對(duì)象
answer=json.loads(r.text)
#你可以自己嘗試print一下r.text的內(nèi)容,然后再閱讀下面的代碼。
result = answer['translateResult'][0][0]['tgt']
return result
class Application(object):
def __init__(self):
self.window = Tk()
self.fanyi = YouDaoFanyi()
self.window.title(u'我的翻譯')
#設(shè)置窗口大小和位置
self.window.geometry('310x370+500+300')
self.window.minsize(310,370)
self.window.maxsize(310,370)
#創(chuàng)建一個(gè)文本框
#self.entry = Entry(self.window)
#self.entry.place(x=10,y=10,width=200,height=25)
#self.entry.bind('<Key-Return>',self.submit1)
self.result_text1 = Text(self.window,background = 'azure')
# 喜歡什么背景色就在這里面找哦,但是有色差,得多試試:http://www.science.smith.edu/dftwiki/index.php/Color_Charts_for_TKinter
self.result_text1.place(x = 10,y = 5,width = 285,height = 155)
self.result_text1.bind('<Key-Return>',self.submit1)
#創(chuàng)建一個(gè)按鈕
#為按鈕添加事件
self.submit_btn = Button(self.window,text=u'翻譯',command=self.submit)
self.submit_btn.place(x=205,y=165,width=35,height=25)
self.submit_btn2 = Button(self.window,text=u'清空',command = self.clean)
self.submit_btn2.place(x=250,y=165,width=35,height=25)
#翻譯結(jié)果標(biāo)題
self.title_label = Label(self.window,text=u'翻譯結(jié)果:')
self.title_label.place(x=10,y=165)
#翻譯結(jié)果
self.result_text = Text(self.window,background = 'light cyan')
self.result_text.place(x = 10,y = 190,width = 285,height = 165)
#回車翻譯
def submit1(self,event):
#從輸入框獲取用戶輸入的值
content = self.result_text1.get(0.0,END).strip().replace('\n',' ')
#把這個(gè)值傳送給服務(wù)器進(jìn)行翻譯
result = self.fanyi.crawl(content)
#將結(jié)果顯示在窗口中的文本框中
self.result_text.delete(0.0,END)
self.result_text.insert(END,result)
#print(content)
def submit(self):
#從輸入框獲取用戶輸入的值
content = self.result_text1.get(0.0,END).strip().replace('\n',' ')
#把這個(gè)值傳送給服務(wù)器進(jìn)行翻譯
result = self.fanyi.crawl(content)
#將結(jié)果顯示在窗口中的文本框中
self.result_text.delete(0.0,END)
self.result_text.insert(END,result)
print(content)
#清空文本域中的內(nèi)容
def clean(self):
self.result_text1.delete(0.0,END)
self.result_text.delete(0.0,END)
def run(self):
self.window.mainloop()
if __name__=='__main__':
app = Application()
app.run()
練習(xí)-圖靈機(jī)器人-參考
第一步:登錄注冊(cè)圖靈機(jī)器人
注冊(cè)登錄,才能創(chuàng)建自己的圖靈機(jī)器人。
根據(jù)幫助中心的“說明書”,我們可以了解如何運(yùn)用這個(gè)新工具~
【講解】
進(jìn)入圖靈機(jī)器人官網(wǎng)[http://www.tuling123.com/](http://www.tuling123.com/),戳進(jìn)幫助中心。
??
就像打開玩具先看說明書一樣,我們來看看官方文檔怎么說怎么用~
??
在功能說明中,我們知道,首先得登錄注冊(cè),用免費(fèi)版本就可以了(當(dāng)然~土豪請(qǐng)隨意),創(chuàng)建機(jī)器人在“機(jī)器人設(shè)置”中,我們用的是第一個(gè)API接入
??
那什么是API呢?通俗地講:
__API就是接口__,就是通道,負(fù)責(zé)一個(gè)程序和其他軟件的溝通,本質(zhì)是預(yù)先定義的函數(shù),而我們不需要了解這個(gè)函數(shù)只是調(diào)用這個(gè)接口就可達(dá)到函數(shù)的效果。
好,接下來我們看下“API V2.0接入文檔”.
??
接口說明:API接口可調(diào)用聊天對(duì)話、語料庫、技能三大模塊的語料。
很好,我們今天想做的聊天機(jī)器人用這個(gè)接口就剛巧合適~
同時(shí),在使用說明中我們可以知曉:
首先創(chuàng)建post請(qǐng)求所需的json數(shù)據(jù),然后向指定的接口發(fā)起post請(qǐng)求即可,而且從參數(shù)說明中可以看到,只有參數(shù) perception 和 userinfo 才是必須的。
對(duì)于userid這個(gè)參數(shù)官方文檔說的是:長度小于32,是用戶的唯一標(biāo)識(shí),這里我們只要?jiǎng)?chuàng)建userid 是長度小于32的字符串即可,說明書已經(jīng)看完啦,來,開始著手做準(zhǔn)備工作!
??
那我們回到主頁,注冊(cè)登錄
??
然后在機(jī)器人管理界面,創(chuàng)建圖靈機(jī)器人,最多可以創(chuàng)建5個(gè),由此得出對(duì)應(yīng)的5個(gè)apikey。(實(shí)際上一個(gè)就夠啦)
apikey是針對(duì)接口訪問的授權(quán)方式。
??
準(zhǔn)備工作做完啦,接下來想想該如何寫代碼
第二步:創(chuàng)建自己的聊天機(jī)器人
請(qǐng)求過程:首先創(chuàng)建post請(qǐng)求所需的json數(shù)據(jù),然后向指定的接口發(fā)起post請(qǐng)求即可,
而且從參數(shù)說明中可以看到,只有參數(shù) perception 和 userinfo 才是必須的
想不清楚的可以看提示哦~
【提示】
userid = str(1)
1 可以替換成任何長度小于32的字符串哦 ~
apikey = str(‘A')
這里的A,記得替換成你自己的apikey哦~
對(duì)咯,還有件小事需要注意一下,有時(shí)候可能你的代碼沒有錯(cuò),但最后顯示加密錯(cuò)誤,那是apikey過期了,不過沒關(guān)系,不是可以最多創(chuàng)建5個(gè)機(jī)器人嘛,換一個(gè)apikey試試就好咯~
【解答】
選擇語言
import requests
import json
userid = str(1)
# 1 可以替換成任何長度小于32的字符串哦
apikey = str(''A)
# 這里的A,記得替換成你自己的apikey哦~
# 創(chuàng)建post函數(shù)
def robot(content):
# 圖靈api
api = r'http://openapi.tuling123.com/openapi/api/v2'
# 創(chuàng)建post提交的數(shù)據(jù)
data = {
'perception': {
'inputText': {
'text': content
}
},
'userInfo': {
'apiKey': apikey,
'userId': userid,
}
}
# 轉(zhuǎn)化為json格式
jsondata = json.dumps(data)
# 發(fā)起post請(qǐng)求
response = requests.post(api, data = jsondata)
# 將返回的json數(shù)據(jù)解碼
robot_res = json.loads(response.content)
# 提取對(duì)話數(shù)據(jù)
print(robot_res['results'][0]['values']['text'])
for x in range(10):
content = input('talk:')
# 輸入對(duì)話內(nèi)容
robot(content)
if x == 10:
break
# 十次之后就結(jié)束對(duì)話,數(shù)字可以改哦,你想幾次就幾次
#當(dāng)然咯,你也可以加一些stopwords,只要說了這些詞就可以終止聊天
while True:
content = input('talk:')
# 輸入對(duì)話內(nèi)容
robot(content)
if content == 'bye':
# 設(shè)置stopwords
break
#但是,我覺得吧,喜歡和聊天機(jī)器人玩的都是話癆,所以,可以最后加個(gè)死循環(huán),如下:
# 創(chuàng)建對(duì)話死循環(huán)
while True:
# 輸入對(duì)話內(nèi)容
content = input('talk:')
robot(content)
這個(gè)練習(xí)可能會(huì)遇到的問題
1、api = r'http://openapi.tuling123.com/openapi/api/v2' 為什么要寫成這種格式,而不是常規(guī)的網(wǎng)頁?為啥有個(gè)r?
加r表示絕對(duì)字符串,這樣里面的\就不會(huì)表達(dá)出其他的意思。r是保持字符串原始值的意思,就是說不對(duì)其中的符號(hào)進(jìn)行轉(zhuǎn)義。因?yàn)閣indows下的目錄字符串中通常有斜杠'\',而斜杠在Python的字符串中有轉(zhuǎn)義的作用。例如:\n表示換行如果路徑中有\(zhòng)new就會(huì)被轉(zhuǎn)義。加上r就是為了避免這種情況~
2、對(duì)話限制問題
目前圖靈機(jī)器人免費(fèi)用戶對(duì)話限制由原先的100次限制剩3次!
練習(xí)-nlpir人工智能-參考
目前網(wǎng)站無法訪問,這個(gè)練習(xí)不用做了哈~
第9關(guān)
練習(xí)-博客達(dá)人-參考
你需要做的事情是:
首先,登錄博客[人人都是蜘蛛俠](https://wordpress-edu-3autumn.localprod.forc.work/wp-login.php)。
然后,在文章《未來已來(三)——同九義何汝秀》中,發(fā)表一個(gè)評(píng)論,這個(gè)評(píng)論中必須要帶有“selenium”這個(gè)詞。
博客登錄頁面:https://wordpress-edu-3autumn.localprod.forc.work/wp-login.php
答這道題的時(shí)候,使用可視模式會(huì)對(duì)運(yùn)行結(jié)果有更直觀的了解,如果你想看到瀏覽器的操作過程,建議你在本地寫好練習(xí)答案,然后再復(fù)制到這里。
【提示】
使用`selenium`操作瀏覽器的方法,就和人一步一步操作的步驟是一樣的:
1. 獲取網(wǎng)頁
2. 輸入用戶名與密碼,點(diǎn)擊登錄
3. 點(diǎn)擊《未來已來(三)——同九義何汝秀》文章標(biāo)題,進(jìn)入文章頁面
4. 找到評(píng)論區(qū),輸入評(píng)論,點(diǎn)擊發(fā)表評(píng)論
用到的知識(shí)點(diǎn)都是`selenium`提取數(shù)據(jù)的方法,以及操作元素的方法。
【解答】
特別提示:
從博客首頁進(jìn)入文章頁面時(shí),需要用到 find_element_by_partial_link_text 通過鏈接的部分文本獲取超鏈接。
發(fā)表評(píng)論之后,不會(huì)再終端返回運(yùn)行結(jié)果,記得去博客文章的頁面去看看自己的評(píng)論有沒有成功~
由于教學(xué)系統(tǒng)中與你本地的瀏覽器設(shè)置方法不同,我給你提供了兩份答案,一份可以在課程系統(tǒng)中運(yùn)行,一份可以在你的本地運(yùn)行。
選擇語言
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.webdriver import RemoteWebDriver
# 獲取用戶輸入的評(píng)論內(nèi)容
while True:
comment_content = input('請(qǐng)輸入你想要的評(píng)論的內(nèi)容,按回車提交:')
if comment_content == '':
print('&' * 5, '評(píng)論內(nèi)容不允許為空', '&' * 5)
else:
break
'''方法一:使用自己電腦上的瀏覽器'''
driver = webdriver.Chrome() # 實(shí)例化瀏覽器對(duì)象
driver.get('https://wordpress-edu-3autumn.localprod.forc.work/wp-login.php') # 訪問頁面
time.sleep(2)
'''方法二:使用教學(xué)系統(tǒng)的瀏覽器設(shè)置,只能在網(wǎng)頁的在線編輯器上運(yùn)行'''
# chrome_options = Options() # 實(shí)例化Option對(duì)象
# chrome_options.add_argument('--headless') # 對(duì)瀏覽器的設(shè)置
# driver = webdriver.Chrome('http://chromedriver.python-class-fos.svc:4444/wd/hub',
# chrome_options.to_capabilities()) # 聲明瀏覽器對(duì)象
# driver.get('https://wordpress-edu-3autumn.localprod.forc.work/wp-login.php') # 訪問頁面
# 定位到用戶名輸入框,輸入用戶名
login_name = driver.find_element_by_id('user_login')
login_name.send_keys('spiderman')
time.sleep(1)
# 定位到密碼輸入框,輸入密碼
password = driver.find_element_by_id('user_pass')
password.send_keys('crawler334566')
# 定位到登錄按鈕,并點(diǎn)擊按鈕
submit_btn = driver.find_element_by_id('wp-submit')
submit_btn.click()
time.sleep(2)
# 通過鏈接的部分文本定位到'《未來已來(三)——同九義何汝秀》'這篇文章
# 獲取到該文章對(duì)應(yīng)的a標(biāo)簽(超鏈接),并點(diǎn)擊鏈接進(jìn)入文章詳情頁
article_link = driver.find_element_by_partial_link_text('同九義何汝秀')
article_link.click()
# 進(jìn)入文章詳情頁,定位到該頁面下編寫評(píng)論的文本框,輸入內(nèi)容
comment_area = driver.find_element_by_id('comment')
comment_area.send_keys(comment_content)
time.sleep(2)
# 定位到提交按鈕,點(diǎn)擊該按鈕提交評(píng)論
comment_submit = driver.find_element_by_id('submit')
comment_submit.click()
# 評(píng)論成功10秒后關(guān)閉瀏覽器
time.sleep(10)
driver.close()
print('#' * 6, '評(píng)論成功,瀏覽器已關(guān)閉', '#' * 6)
練習(xí)-Python之禪-參考
題目要求
獲取網(wǎng)站[你好,蜘蛛俠!](https://localprod.pandateacher.com/python-manuscript/hello-spiderman/)的Python之禪中文英對(duì)照文本。
需要通過兩種方法獲?。?/p>
- 只使用`selenium`
- `selenium`與`BeautifulSoup`配合
【講解】
[你好,蜘蛛俠!](https://localprod.pandateacher.com/python-manuscript/hello-spiderman/)是一個(gè)動(dòng)態(tài)網(wǎng)頁,URL:https://localprod.pandateacher.com/python-manuscript/hello-spiderman/
Python之禪的內(nèi)容沒有存在網(wǎng)頁源代碼中,無法通過`requests.get()`與`BeautifulSoup`提取“Python之禪”的內(nèi)容,不過,我們可以通過`selenium`獲取到。
方法如下:
0. 使用`selenium`獲取網(wǎng)頁
1. 輸入你喜歡的老師和助教,點(diǎn)擊提交
2. 提取`Elements`中渲染完成的完整網(wǎng)頁源代碼中的,中英文對(duì)照的Python之禪
我在課堂講解中帶你做過前兩步了,第三步正是你現(xiàn)在需要做的。
我們可以用兩種方式完成它~
第一種方法:
只使用`selenium`。
第二種方法:
使用`selenium`配合`BeautifulSoup`。
第一種方法:selenium
這次我們要用`selenium`單獨(dú)完成這個(gè)爬蟲。獲取數(shù)據(jù)、解析數(shù)據(jù)、提取數(shù)據(jù)這三個(gè)步驟全部都由`selenium`來完成,寫代碼吧~
【提示】
前面的步驟,在關(guān)卡課程中都已經(jīng)講過,現(xiàn)在要做的是,在它的基礎(chǔ)之上,獲取中英文的“Python之禪”內(nèi)容。
中文和英文版的“Python之禪”都在同樣的標(biāo)簽中。所以,需要先獲取所有的`class_='content'`標(biāo)簽,然后再從中分別提取標(biāo)題與正文。
具體的方法都寫在了代碼注釋中。
由于教學(xué)系統(tǒng)中與你本地的瀏覽器設(shè)置方法不同,我給你提供了兩份答案,一份可以在課程系統(tǒng)中運(yùn)行,一份可以在你的本地運(yùn)行。
【解答】
選擇語言
# 下面是只能在爬蟲課系統(tǒng)中運(yùn)行的答案:
from selenium.webdriver.chrome.webdriver import RemoteWebDriver # 從selenium庫中調(diào)用RemoteWebDriver模塊
from selenium.webdriver.chrome.options import Options # 從options模塊中調(diào)用Options類
import time
chrome_options = Options() # 實(shí)例化Option對(duì)象
chrome_options.add_argument('--headless') # 把Chrome設(shè)置為靜默模式
driver = RemoteWebDriver('http://chromedriver.python-class-fos.svc:4444/wd/hub', chrome_options.to_capabilities()) # 設(shè)置瀏覽器引擎為遠(yuǎn)程瀏覽器
chrome_options = Options() # 實(shí)例化Option對(duì)象
chrome_options.add_argument('--headless') # 把Chrome設(shè)置為靜默模式
driver = RemoteWebDriver('http://chromedriver.python-class-fos.svc:4444/wd/hub', chrome_options.to_capabilities()) # 設(shè)置瀏覽器引擎為遠(yuǎn)程瀏覽器
driver.get('https://localprod.pandateacher.com/python-manuscript/hello-spiderman/') # 訪問頁面
time.sleep(2) # 暫停兩秒,等待瀏覽器緩沖
teacher = driver.find_element_by_id('teacher') # 找到【請(qǐng)輸入你喜歡的老師】下面的輸入框位置
teacher.send_keys('必須是吳楓呀') # 輸入文字
assistant = driver.find_element_by_name('assistant') # 找到【請(qǐng)輸入你喜歡的助教】下面的輸入框位置
assistant.send_keys('都喜歡') # 輸入文字
button = driver.find_element_by_class_name('sub') # 找到【提交】按鈕
button.click() # 點(diǎn)擊【提交】按鈕
time.sleep(1)
contents = driver.find_elements_by_class_name('content') # 定位到Python之禪所在的標(biāo)簽
for content in contents:
title = content.find_element_by_tag_name('h1').text # 提取標(biāo)題
chan = content.find_element_by_tag_name('p').text # 提取正文
print(title + '\n' + chan + '\n') # 打印標(biāo)題與正文
driver.close()
選擇語言
# 下面是只能在你的本地運(yùn)行的答案:
from selenium import webdriver # 從selenium庫中調(diào)用webdriver模塊
import time
driver = webdriver.Chrome() # 聲明瀏覽器對(duì)象
driver.get('https://localprod.pandateacher.com/python-manuscript/hello-spiderman/') # 訪問頁面
time.sleep(2) # 暫停兩秒,等待瀏覽器緩沖
teacher = driver.find_element_by_id('teacher') # 找到【請(qǐng)輸入你喜歡的老師】下面的輸入框位置
teacher.send_keys('必須是吳楓呀') # 輸入文字
assistant = driver.find_element_by_name('assistant') # 找到【請(qǐng)輸入你喜歡的助教】下面的輸入框位置
assistant.send_keys('都喜歡') # 輸入文字
button = driver.find_element_by_class_name('sub') # 找到【提交】按鈕
button.click() # 點(diǎn)擊【提交】按鈕
time.sleep(1)
contents = driver.find_elements_by_class_name('content') # 定位到Python之禪所在的標(biāo)簽
for content in contents:
title = content.find_element_by_tag_name('h1').text # 提取標(biāo)題
chan = content.find_element_by_tag_name('p').text # 提取正文
print(title + '\n' + chan + '\n') # 打印標(biāo)題與正文
driver.close()
第二種方法:selenium 與 BeautifulSoup配合
先用`selenium`獲取到渲染完成的`Elements`中的網(wǎng)頁源代碼,然后,`BeautifulSoup`登場(chǎng)解析和提取數(shù)據(jù)。
【提示】
爬取到的文字中,前面會(huì)有一些空格,可以使用`replace(' ','')`去掉文字前面的空格。
這是字符串對(duì)象的一個(gè)方法,它的意思是,把第一個(gè)參數(shù)的字符串用第二個(gè)參數(shù)的字符串替代。
【解答】
具體的方法都寫在了代碼注釋中。
由于教學(xué)系統(tǒng)中與你本地的瀏覽器設(shè)置方法不同,我給你提供了兩份答案,一份可以在課程系統(tǒng)中運(yùn)行,一份可以在你的本地運(yùn)行。
選擇語言
# 下面是只能在爬蟲課系統(tǒng)中運(yùn)行的答案:
from selenium.webdriver.chrome.webdriver import RemoteWebDriver # 從selenium庫中調(diào)用RemoteWebDriver模塊
from selenium.webdriver.chrome.options import Options # 從options模塊中調(diào)用Options類
from bs4 import BeautifulSoup
import time
chrome_options = Options() # 實(shí)例化Option對(duì)象
chrome_options.add_argument('--headless') # 把Chrome設(shè)置為靜默模式
driver = RemoteWebDriver('http://chromedriver.python-class-fos.svc:4444/wd/hub', chrome_options.to_capabilities()) # 設(shè)置瀏覽器引擎為遠(yuǎn)程瀏覽器
driver.get('https://localprod.pandateacher.com/python-manuscript/hello-spiderman/') # 訪問頁面
time.sleep(2) # 暫停兩秒,等待瀏覽器緩沖
teacher = driver.find_element_by_id('teacher') # 定位到【請(qǐng)輸入你喜歡的老師】下面的輸入框位置
teacher.send_keys('必須是吳楓呀') # 輸入文字
assistant = driver.find_element_by_name('assistant') # 定位到【請(qǐng)輸入你喜歡的助教】下面的輸入框位置
assistant.send_keys('都喜歡') # 輸入文字
button = driver.find_element_by_class_name('sub') # 定位到【提交】按鈕
button.click() # 點(diǎn)擊【提交】按鈕
time.sleep(1) # 等待一秒
pageSource = driver.page_source # 獲取頁面信息
soup = BeautifulSoup(pageSource,'html.parser') # 使用bs解析網(wǎng)頁
contents = soup.find_all(class_='content') # 找到源代碼Python之禪中文版和英文版所在的元素
for content in contents: # 遍歷列表
title = content.find('h1').text # 提取標(biāo)題
chan = content.find('p').text.replace(' ','') # 提取Python之禪的正文,并且去掉文字前面的所有空格
print(title + chan + '\n') # 打印Python之禪的標(biāo)題與正文
driver.close()
# 下面是只能在你的本地運(yùn)行的答案:
from selenium import webdriver # 從selenium庫總調(diào)用webdriver模塊
import time
from bs4 import BeautifulSoup
driver = webdriver.Chrome() # 聲明瀏覽器對(duì)象
driver.get('https://localprod.pandateacher.com/python-manuscript/hello-spiderman/') # 訪問頁面
time.sleep(2) # 暫停兩秒,等待瀏覽器緩沖
teacher = driver.find_element_by_id('teacher') # 定位到【請(qǐng)輸入你喜歡的老師】下面的輸入框位置
teacher.send_keys('必須是吳楓呀') # 輸入文字
assistant = driver.find_element_by_name('assistant') # 定位到【請(qǐng)輸入你喜歡的助教】下面的輸入框位置
assistant.send_keys('都喜歡') # 輸入文字
button = driver.find_element_by_class_name('sub') # 定位到【提交】按鈕
button.click() # 點(diǎn)擊【提交】按鈕
time.sleep(1) # 等待一秒
pageSource = driver.page_source # 獲取頁面信息
soup = BeautifulSoup(pageSource,'html.parser') # 使用bs解析網(wǎng)頁
contents = soup.find_all(class_='content') # 找到源代碼Python之禪中文版和英文版所在的元素
for content in contents: # 遍歷列表
title = content.find('h1').text # 提取標(biāo)題
chan = content.find('p').text.replace(' ','') # 提取Python之禪的正文,并且去掉文字前面的所有空格
print(title + chan + '\n') # 打印Python之禪的標(biāo)題與正文
driver.close()
第10關(guān)
練習(xí)-周末吃什么-參考
第一步:明確目標(biāo)
先明確目標(biāo):我們?cè)诘?關(guān)爬取了下廚房網(wǎng)站中的“本周最受歡迎菜譜”,現(xiàn)在,我們完善這個(gè)程序,讓程序在每個(gè)周五爬取數(shù)據(jù),并把菜譜發(fā)送到我們的郵箱。
【講解】
先明確目標(biāo):我們?cè)诘?關(guān)爬取了下廚房網(wǎng)站中的“本周最受歡迎菜譜”,現(xiàn)在,我們完善這個(gè)程序,讓程序在每個(gè)周五爬取數(shù)據(jù),并把菜譜發(fā)送到我們的郵箱。
該項(xiàng)目和第10關(guān)課堂的項(xiàng)目是非常相似的。
第二步:分析過程
再分析過程:這個(gè)程序一共分為三部分:爬蟲、通知和定時(shí)。
【講解】
這個(gè)程序一共分為三部分,知識(shí)我們都掌握了。
0.爬蟲:爬取下廚房網(wǎng)站中本周最歡迎菜譜的菜名、鏈接、原材料。
1.通知:用smtplib、email庫來發(fā)送郵件。
2.定時(shí):用schedule和time庫定時(shí)執(zhí)行程序。
我們分別寫出來,然后封裝成函數(shù)。
先把每個(gè)程序?qū)懗鰜?,然后拼裝到一起;鑒于爬蟲程序已經(jīng)學(xué)過,就直接把代碼提供給大家。
第三步:代碼實(shí)現(xiàn)
接下來就是寫代碼啦。
0.爬蟲:爬蟲代碼已經(jīng)在課堂上學(xué)過,所以直接把爬蟲代碼提供給大家,并請(qǐng)大家先封裝爬蟲代碼:
選擇語言
import requests
from bs4 import BeautifulSoup
res_foods = requests.get('http://www.xiachufang.com/explore/')
bs_foods = BeautifulSoup(res_foods.text,'html.parser')
list_foods = bs_foods.find_all('div',class_='info pure-u')
list_all = []
for food in list_foods:
tag_a = food.find('a')
name = tag_a.text[17:-13]
URL = 'http://www.xiachufang.com'+tag_a['href']
tag_p = food.find('p',class_='ing ellipsis')
ingredients = tag_p.text[1:-1]
list_all.append([name,URL,ingredients])
print(list_all)
1.郵件:郵件代碼是第10關(guān)所學(xué)的內(nèi)容,下面提供代碼給大家,但最好是回憶不起來再看;寫完代碼后請(qǐng)大家封裝代碼。
(仍然提醒同學(xué)們,學(xué)習(xí)系統(tǒng)會(huì)記錄大家輸入的內(nèi)容。考慮到信息隱私的問題,大家不要在這里輸入自己的郵箱密碼或賬號(hào)。因此,請(qǐng)你在本地運(yùn)行郵件相關(guān)的代碼)
選擇語言
import smtplib
from email.mime.text import MIMEText
from email.header import Header
#引入smtplib、MIMETex和Header
mailhost='smtp.qq.com'
#把qq郵箱的服務(wù)器地址賦值到變量mailhost上,地址應(yīng)為字符串格式
qqmail = smtplib.SMTP()
#實(shí)例化一個(gè)smtplib模塊里的SMTP類的對(duì)象,這樣就可以調(diào)用SMTP對(duì)象的方法和屬性了
qqmail.connect(mailhost,25)
#連接服務(wù)器,第一個(gè)參數(shù)是服務(wù)器地址,第二個(gè)參數(shù)是SMTP端口號(hào)。
#以上,皆為連接服務(wù)器。
account = input('請(qǐng)輸入你的郵箱:')
#獲取郵箱賬號(hào),為字符串格式
password = input('請(qǐng)輸入你的密碼:')
#獲取郵箱密碼,為字符串格式
qqmail.login(account,password)
#登錄郵箱,第一個(gè)參數(shù)為郵箱賬號(hào),第二個(gè)參數(shù)為郵箱密碼
#以上,皆為登錄郵箱。
receiver=input('請(qǐng)輸入收件人的郵箱:')
#獲取收件人的郵箱。
content=input('請(qǐng)輸入郵件正文:')
#輸入你的郵件正文,為字符串格式
message = MIMEText(content, 'plain', 'utf-8')
#實(shí)例化一個(gè)MIMEText郵件對(duì)象,該對(duì)象需要寫進(jìn)三個(gè)參數(shù),分別是郵件正文,文本格式和編碼
subject = input('請(qǐng)輸入你的郵件主題:')
#輸入你的郵件主題,為字符串格式
message['Subject'] = Header(subject, 'utf-8')
#在等號(hào)的右邊是實(shí)例化了一個(gè)Header郵件頭對(duì)象,該對(duì)象需要寫入兩個(gè)參數(shù),分別是郵件主題和編碼,然后賦值給等號(hào)左邊的變量message['Subject']。
#以上,為填寫主題和正文。
try:
qqmail.sendmail(account, receiver, message.as_string())
print ('郵件發(fā)送成功')
except:
print ('郵件發(fā)送失敗')
qqmail.quit()
#以上為發(fā)送郵件和退出郵箱
2.定時(shí):定時(shí)功能是第10關(guān)教的內(nèi)容,代碼如下,下面提供代碼給大家,但最好回憶不起來再看;寫完代碼后請(qǐng)大家封裝代碼。
選擇語言
import schedule
import time
#引入schedule和time
def job():
print('I'm working...')
#定義一個(gè)叫job的函數(shù),函數(shù)的功能是打印'I'm working...'
schedule.every(10).minutes.do(job) #部署每10分鐘執(zhí)行一次job()函數(shù)的任務(wù)
schedule.every().hour.do(job) #部署每×小時(shí)執(zhí)行一次job()函數(shù)的任務(wù)
schedule.every().day.at('10:30').do(job) #部署在每天的10:30執(zhí)行job()函數(shù)的任務(wù)
schedule.every().monday.do(job) #部署每個(gè)星期一執(zhí)行job()函數(shù)的任務(wù)
schedule.every().wednesday.at('13:15').do(job)#部署每周三的13:15執(zhí)行函數(shù)的任務(wù)
while True:
schedule.run_pending()
time.sleep(1)
【解答】
老師提供的參考答案是這樣的:
選擇語言
import requests
import smtplib
import schedule
import time
from bs4 import BeautifulSoup
from email.mime.text import MIMEText
from email.header import Header
account = input('請(qǐng)輸入你的郵箱:')
password = input('請(qǐng)輸入你的密碼:')
receiver = input('請(qǐng)輸入收件人的郵箱:')
def recipe_spider():
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
res_foods = requests.get('http://www.xiachufang.com/explore/',headers=headers)
bs_foods = BeautifulSoup(res_foods.text,'html.parser')
list_foods = bs_foods.find_all('div',class_='info pure-u')
list_all = ''
num=0
for food in list_foods:
num=num+1
tag_a = food.find('a')
name = tag_a.text.strip()
url = 'http://www.xiachufang.com'+tag_a['href']
tag_p = food.find('p',class_='ing ellipsis')
ingredients = tag_p.text.strip()
food_info = '''
序號(hào): %s
菜名: %s
鏈接: %s
原料: %s
'''%(num,name,url,ingredients)
list_all=list_all+food_info
return(list_all)
def send_email(list_all):
global account,password,receiver
mailhost='smtp.qq.com'
qqmail = smtplib.SMTP()
qqmail.connect(mailhost,25)
qqmail.login(account,password)
content= '親愛的,本周的熱門菜譜如下'+list_all
message = MIMEText(content, 'plain', 'utf-8')
subject = '周末吃個(gè)啥'
message['Subject'] = Header(subject, 'utf-8')
try:
qqmail.sendmail(account, receiver, message.as_string())
print ('郵件發(fā)送成功')
except:
print ('郵件發(fā)送失敗')
qqmail.quit()
def job():
print('開始一次任務(wù)')
list_all = recipe_spider()
send_email(list_all)
print('任務(wù)完成')
schedule.every().friday.at('18:00').do(job)#部署每周三的13:15執(zhí)行函數(shù)的任務(wù)
while True:
schedule.run_pending()
time.sleep(1)
練習(xí)-看個(gè)電影吧-參考
第一步:明確目標(biāo)
先明確目標(biāo):每個(gè)周五,程序在豆瓣TOP250榜單中隨機(jī)選取三部電影,然后去爬取三部電影的下載鏈接,并把鏈接發(fā)送到我們的郵箱。
【講解】
先明確目標(biāo):每個(gè)周五,程序在豆瓣TOP250榜單中隨機(jī)選取三部電影,然后去爬取三部電影的下載鏈接,并把鏈接發(fā)送到我們的郵箱。該項(xiàng)目和第10關(guān)課堂的是非常相似的。
第二步:分析過程
我們來看看這個(gè)項(xiàng)目的實(shí)現(xiàn)思路。
【講解】
這個(gè)程序一共分為四部分:
??
0.電影榜單爬蟲:爬取豆瓣電影Top250的榜單,并存儲(chǔ)文件到本地。
1.電影鏈接爬蟲:每周五讀取榜單中的三部電影,然后去爬取電影的下載鏈接。
2.通知功能:再把爬到的鏈接以郵件的形式發(fā)送給自己。
3.定時(shí)功能:用schedule和time庫定時(shí)執(zhí)行程序。
可以把4段代碼分別寫出來,然后封裝成函數(shù)。鑒于爬蟲程序已經(jīng)做過練習(xí),會(huì)直接把代碼提供給大家。
電影榜單的爬蟲是第3關(guān)課后的必做練習(xí),電影鏈接的爬蟲是第3關(guān)的選做練習(xí),所以該練習(xí)的重點(diǎn)不會(huì)放在爬蟲上。
第三步:代碼實(shí)現(xiàn)(上)
【代碼實(shí)現(xiàn)】又分為上中下。上、中分別把四段代碼寫出來,下是封裝組裝代碼。
上:每周五晚上去豆瓣電影Top250的榜單上隨機(jī)抽取3部,然后去下載這3部電影的鏈接,并打印出來。
先把兩段爬蟲的代碼提供給大家,請(qǐng)大家先閱讀,然后去寫代碼。(當(dāng)然,你用你自己寫的代碼也是一樣的,只要最后實(shí)現(xiàn)的功能和題目一致)
選擇語言
#這是爬取豆瓣電影Top250,并存為本地csv的代碼
import requests, random, csv
from bs4 import BeautifulSoup
csv_file=open('movieTop.csv', 'w', newline='',encoding='utf-8')
writer = csv.writer(csv_file)
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
title = titles.find('span', class_='title').text
list1 = [title]
writer.writerow(list1)
csv_file.close()
選擇語言
# 這是爬電影的下載鏈接的代碼
import requests
from bs4 import BeautifulSoup
from urllib.request import quote
movie=input('你想看什么電影?')
gbkmovie = movie.encode('gbk')
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
urlsearch = 'http://s.ygdy8.com/plus/so.php?typeid=1&keyword='+quote(gbkmovie)
res = requests.get(urlsearch,headers=headers)
res.encoding='gbk'
soup_movie = BeautifulSoup(res.text,'html.parser')
urlpart=soup_movie.find(class_='co_content8').find_all('table')
if urlpart:
urlpart=urlpart[0].find('a')['href']
urlmovie='https://www.ygdy8.com/'+urlpart
res1=requests.get(urlmovie)
res1.encoding='gbk'
soup_movie1=BeautifulSoup(res1.text,'html.parser')
urldownload=soup_movie1.find('div',id='Zoom').find('span').find('table').find('a')['href']
print(urldownload)
else:
print('沒有'+movie+'的鏈接')
好,現(xiàn)在,我們需要先讀取存儲(chǔ)到本地的電影榜單的csv文件,然后用random庫來隨機(jī)抽取三部電影,再去下載相應(yīng)的電影鏈接,并把電影鏈接打印出來。
請(qǐng)開始寫代碼吧。
【提示】
如果對(duì)這里的爬蟲代碼有疑惑,建議先完成第3關(guān)的練習(xí)和第6關(guān)的練習(xí)。
【解答】
選擇語言
import requests,csv,random
from bs4 import BeautifulSoup
from urllib.request import quote
# 以上,為引入相應(yīng)的庫。
csv_file=open('movieTop.csv', 'w', newline='',encoding='utf-8')
writer = csv.writer(csv_file)
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
title = titles.find('span', class_='title').text
list1 = [title]
writer.writerow(list1)
csv_file.close()
# 以上,為爬取豆瓣電影Top250的榜單,并存儲(chǔ)為本地的csv文件。
movielist=[]
csv_file=open('movieTop.csv','r',newline='',encoding='utf-8')
reader=csv.reader(csv_file)
for row in reader:
movielist.append(row[0])
# 以上,為讀取豆瓣電影Top250榜單的csv文件,并寫入列表movielist中。
three_movies=random.sample(movielist,3)
# 以上,是從列表movielist中,隨機(jī)抽取三部電影,取出來的是一個(gè)列表。
for movie in three_movies:
# 以上,是把電影名從列表中取出來,并把其數(shù)據(jù)類型變?yōu)樽址?。下面開始,就是你熟悉的下載電影鏈接的代碼了。
gbkmovie = movie.encode('gbk')
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
urlsearch = 'http://s.ygdy8.com/plus/so.php?typeid=1&keyword='+quote(gbkmovie)
res = requests.get(urlsearch,herders=headers)
res.encoding='gbk'
soup_movie = BeautifulSoup(res.text,'html.parser')
urlpart=soup_movie.find(class_='co_content8').find_all('table')
if urlpart:
urlpart=urlpart[0].find('a')['href']
urlmovie='https://www.ygdy8.com/'+urlpart
res1=requests.get(urlmovie)
res1.encoding='gbk'
soup_movie1=BeautifulSoup(res1.text,'html.parser')
urldownload=soup_movie1.find('div',id='Zoom').find('span').find('table').find('a')['href']
content=movie+'\n'+urldownload
print(content)
else:
content='沒有'+movie+'的下載鏈接'
print(content)
第四步:代碼實(shí)現(xiàn)(中)
接下來,我們來完成發(fā)送郵件,以及定時(shí)功能的代碼,然后在下一步我們?cè)俜庋b、組合四段代碼。
郵件代碼是第10關(guān)所學(xué)的內(nèi)容,下面提供代碼給大家。
(仍然提醒同學(xué)們,學(xué)習(xí)系統(tǒng)會(huì)記錄大家輸入的內(nèi)容??紤]到信息隱私的問題,大家不要在這里輸入自己的郵箱密碼或賬號(hào)。因此,請(qǐng)你在本地運(yùn)行郵件相關(guān)的代碼)
選擇語言
import smtplib
from email.mime.text import MIMEText
from email.header import Header
#引入smtplib、MIMETex和Header
mailhost='smtp.qq.com'
#把qq郵箱的服務(wù)器地址賦值到變量mailhost上,地址應(yīng)為字符串格式
qqmail = smtplib.SMTP()
#實(shí)例化一個(gè)smtplib模塊里的SMTP類的對(duì)象,這樣就可以調(diào)用SMTP對(duì)象的方法和屬性了
qqmail.connect(mailhost,25)
#連接服務(wù)器,第一個(gè)參數(shù)是服務(wù)器地址,第二個(gè)參數(shù)是SMTP端口號(hào)。
#以上,皆為連接服務(wù)器。
account = input('請(qǐng)輸入你的郵箱:')
#獲取郵箱賬號(hào),為字符串格式
password = input('請(qǐng)輸入你的密碼:')
#獲取郵箱密碼,為字符串格式
qqmail.login(account,password)
#登錄郵箱,第一個(gè)參數(shù)為郵箱賬號(hào),第二個(gè)參數(shù)為郵箱密碼
#以上,皆為登錄郵箱。
receiver=input('請(qǐng)輸入收件人的郵箱:')
#獲取收件人的郵箱。
#content為上面的電影鏈接
#輸入你的郵件正文,為字符串格式
message = MIMEText(content, 'plain', 'utf-8')
#實(shí)例化一個(gè)MIMEText郵件對(duì)象,該對(duì)象需要寫進(jìn)三個(gè)參數(shù),分別是郵件正文,文本格式和編碼
subject = '電影鏈接'
#輸入你的郵件主題,為字符串格式
message['Subject'] = Header(subject, 'utf-8')
#在等號(hào)的右邊是實(shí)例化了一個(gè)Header郵件頭對(duì)象,該對(duì)象需要寫入兩個(gè)參數(shù),分別是郵件主題和編碼,然后賦值給等號(hào)左邊的變量message['Subject']。
#以上,為填寫主題和正文。
try:
qqmail.sendmail(account, receiver, message.as_string())
print ('郵件發(fā)送成功')
except:
print ('郵件發(fā)送失敗')
qqmail.quit()
#以上為發(fā)送郵件和退出郵箱
#定時(shí)功能是第10關(guān)教的內(nèi)容,代碼如下,下面提供代碼給大家,但最好回憶不起來再看。
import schedule
import time
#引入schedule和time
def job():
print('I'm working...')
#定義一個(gè)叫job的函數(shù),函數(shù)的功能是打印'I'm working...'
schedule.every(10).minutes.do(job) #部署每10分鐘執(zhí)行一次job()函數(shù)的任務(wù)
schedule.every().hour.do(job) #部署每×小時(shí)執(zhí)行一次job()函數(shù)的任務(wù)
schedule.every().day.at('10:30').do(job)#部署每天的10:30執(zhí)行job()函數(shù)任務(wù)
schedule.every().monday.do(job) #部署每個(gè)星期一執(zhí)行job()函數(shù)的任務(wù)
schedule.every().wednesday.at('13:15').do(job)
#部署每周三的13:15執(zhí)行函數(shù)的任務(wù)
while True:
schedule.run_pending()
time.sleep(1)
【解答】
老師提供的參考答案是這樣的:
選擇語言
import requests,csv,random,smtplib,schedule,time
from bs4 import BeautifulSoup
from urllib.request import quote
from email.mime.text import MIMEText
from email.header import Header
def get_movielist():
csv_file=open('movieTop.csv', 'w', newline='',encoding='utf-8')
writer = csv.writer(csv_file)
for x in range(10):
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
url = 'https://movie.douban.com/top250?start=' + str(x*25) + '&filter='
res = requests.get(url,headers=headers)
bs = BeautifulSoup(res.text, 'html.parser')
bs = bs.find('ol', class_='grid_view')
for titles in bs.find_all('li'):
title = titles.find('span', class_='title').text
list1 = [title]
writer.writerow(list1)
csv_file.close()
def get_randommovie():
movielist=[]
csv_file=open('movieTop.csv','r',newline='',encoding='utf-8')
reader=csv.reader(csv_file)
for row in reader:
movielist.append(row[0])
three_movies=random.sample(movielist,3)
contents=''
for movie in three_movies:
gbkmovie = movie.encode('gbk')
headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
urlsearch = 'http://s.ygdy8.com/plus/so.php?typeid=1&keyword='+quote(gbkmovie)
res = requests.get(urlsearch,headers=headers)
res.encoding='gbk'
soup_movie = BeautifulSoup(res.text,'html.parser')
urlpart=soup_movie.find(class_='co_content8').find_all('table')
if urlpart:
urlpart=urlpart[0].find('a')['href']
urlmovie='https://www.ygdy8.com/'+urlpart
res1=requests.get(urlmovie)
res1.encoding='gbk'
soup_movie1=BeautifulSoup(res1.text,'html.parser')
urldownload=soup_movie1.find('div',id='Zoom').find('span').find('table').find('a')['href']
content=movie+'\n'+urldownload+'\n\n'
print(content)
contents=contents+content
else:
content='沒有'+movie+'的下載鏈接'
print(content)
return contents
def send_movielink(contents):
mailhost='smtp.qq.com'
qqmail = smtplib.SMTP()
qqmail.connect(mailhost,25)
account = '×××××××××@qq.com' # 因?yàn)槭亲约喊l(fā)給自己,所以郵箱賬號(hào)、密碼都可以提前設(shè)置好,當(dāng)然,也可以發(fā)給別人啦
password = '×××××××××××××××' # 因?yàn)槭亲约喊l(fā)給自己,所以郵箱賬號(hào)、密碼都可以提前設(shè)置好,當(dāng)然,也可以發(fā)給別人啦。
qqmail.login(account,password)
receiver='×××××××××@qq.com' # 因?yàn)槭亲约喊l(fā)給自己,所以郵箱賬號(hào)、密碼都可以提前設(shè)置好,當(dāng)然,也可以發(fā)給別人啦。
message = MIMEText(contents, 'plain', 'utf-8')
subject = '電影鏈接'
message['Subject'] = Header(subject, 'utf-8')
try:
qqmail.sendmail(account, receiver, message.as_string())
print ('郵件發(fā)送成功')
except:
print ('郵件發(fā)送失敗')
qqmail.quit()
def job():
get_movielist()
contents=get_randommovie()
send_movielink(contents)
schedule.every().friday.at('18:00').do(job)
while True:
schedule.run_pending()
time.sleep(1)