微博搜索采集時,默認情況下只顯示當前頁數(shù)據(jù)。如果搜索的關鍵詞是熱詞,當前頁數(shù)據(jù)的時間范圍可能只有三五分鐘。所以,如果要把數(shù)據(jù)采集全,則必須登錄。
在大批量采集時,必須使用賬號構建cookie池,并根據(jù)cookie有效期實時更新已過期的cookie,下面主要實現(xiàn)基于Pyppeteer的微博登錄,供大家參考。
import asyncio, time
from com.fy.plugs.browser.pyppeteer.PyppeteerBrowser import PyppeteerBrowser
from com.fy.utils.date.DateUtils import Date_Utils
class WeiBoLogin:
def __init__(self):
self.pb=PyppeteerBrowser()
self.du=Date_Utils()
def login(self):
url="https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=https%3A%2F%2Fm.weibo.cn%2F"
userDataDir="d://pyppeteer" + str(self.du.getCurrentTimeStr_Year())
asyncio.get_event_loop() .run_until_complete(self.pb.getbrowser(False, userDataDir))
asyncio.get_event_loop() .run_until_complete(self.pb.open(url, 60))
time.sleep(10)
asyncio.get_event_loop() .run_until_complete(self.pb.inputKw(None, "#loginName", "用戶名"))
time.sleep(1)
asyncio.get_event_loop() .run_until_complete(self.pb.inputKw(None, "#loginPassword", "密碼"))
time.sleep(1)
eles=asyncio.get_event_loop() .run_until_complete(self.pb.getElementsByXpaths(None, '//*[@id="loginAction"]'))
asyncio.get_event_loop() .run_until_complete(self.pb.clickByEle(eles[0]))
time.sleep(100)
if __name__=='__main__':
sbl=WeiBoLogin()
sbl.login()
import asyncio, tkinter, traceback
import time
from pyppeteer import launch
from com.fy.utils.http.UserAgentUtils import UserAgentUtils
from com.fy.utils.hash.HashUtils import Hash_Utils
from com.fy.utils.file.FileUtils import File_Utils
class PyppeteerBrowser:
def __init__(self):
self.hash=Hash_Utils()
self.url=None
self.ua=UserAgentUtils()
#"""使用tkinter獲取屏幕大小""")
def screen_size(self):
tk=tkinter.Tk()
width=tk.winfo_screenwidth()
height=tk.winfo_screenheight()
tk.quit()
return width, height
async def getbrowser(self, headless=False, userDataDir=None):
args=[ "--start-maximized", '--no-sandbox', "--disable-infobars" , "--log-level=3"]
parameters={}
if userDataDir==None:
parameters={'headless': headless, #是否打開瀏覽器;False:打開瀏覽器;True:進程中運行;
'args': args,
'dumpio': True #'dumpio': True:解決chromium瀏覽器多開頁面卡死問題。
}
else:
parameters={'headless': headless, #是否打開瀏覽器;False:打開瀏覽器;True:進程中運行;
'args': args,
"userDataDir": userDataDir,
'dumpio': True #'dumpio': True:解決chromium瀏覽器多開頁面卡死問題。
}
#注意:同一個用戶目錄(userDataDir)不能被兩個chrome進程使用,如果你要多開,記得分別指定用戶目錄。否則會報編碼錯誤。
self.browser=await launch(parameters)
self.page=await self.browser.newPage()#在此瀏覽器上創(chuàng)建新頁面并返回其對象。
width, height=self.screen_size()
# 設置網(wǎng)頁可視區(qū)域大小
await self.page.setViewport({
"width": width,
"height": height
})
# 是否啟用JS,enabled設為False,則無渲染效果
await self.page.setJavaScriptEnabled(enabled=True)
#設置請求頭userAgent
await self.page.setUserAgent(self.ua.getheaders())
await self.preventCheckWebdriver(self.page)
print("構造瀏覽器對象完畢....", self.page)
#獲取當前操作的界面
async def getPage(self):
return self.page
#獲取當前page對象的鏈接;
async def getCurUrl(self, page):
if page==None:
page=self.page
return await page.url
#打開一個新的界面;)
async def getnewpage(self):
return await self.browser.newPage()
#獲取當前操作的界面重新加載
async def reload(self):
await self.page.reload()
#當前操作界面返回
async def goBack(self):
await self.page.goBack()
#獲取當前操作的界面的URL
async def getPageUrl(self):
await self.page.url()
#打開連接;
async def open(self, url, timeout=60):
try:
if url==None:
print("當前傳入的【url】不能為空,參數(shù)錯誤!!")
self.url=url
print("打開網(wǎng)頁:" + (url))
self.res=await self.page.goto(url, options={'timeout':int(timeout * 1000)})#打開連接;
await asyncio.sleep(1)#強行等待3秒
status=await self.res.status
curUrl=await self.page.url
await self.preventCheckWebdriver(self.page)
return status, curUrl
except:return 404, None
async def preventCheckWebdriver(self, page):
if page==None:
page=self.page
await page.evaluate('''()=>{ Object.defineProperties(navigator,{ webdriver:{ get: ()=> undefined } }) }''') # 以下為插入中間js,將淘寶會為了檢測瀏覽器而調用的js修改其結果。
await page.evaluate('''()=>{ window.navigator.chrome={ runtime: {}, }; }''')
await page.evaluate('''()=>{ Object.defineProperty(navigator, 'languages', { get: ()=> ['en-US', 'en'] }); }''')
await page.evaluate('''()=>{ Object.defineProperty(navigator, 'plugins', { get: ()=> [1, 2, 3, 4, 5,6], }); }''')
async def closeBrowser(self, browser):
if browser==None:
browser=self.browser
try:
await browser.close()
except:pass
async def closePage(self, page):
if page==None:
page=self.page
await page.close()
async def closeNumPage(self, number:"號碼從0開始"):
pages=await self.browser.pages()
await pages[number].close()
return True
async def retainLastPage(self):
pages=await self.browser.pages()
num=0
for page in pages:
if num !=(len(pages) - 1):
await page.close()
else:
self.page=page
num +=1
async def gerReponseStatus(self):
try:return await self.res.status # 響應狀態(tài)
except:return 200
async def screenshot(self, page):
hashCode=self.hash.getMd5Hash(self.url)
if page==None:
page=self.page
await page.screenshot({'path': './screenshots/' + str(hashCode) + '.png'})
async def getHeader(self):
return await self.res.headers # 響應頭;
async def scrollToButtom(self, page):
if page==None:
page=self.page
await page.evaluate('window.scrollBy(0, document.body.scrollHeight)')
async def getCookies(self, page):
if page==None:
page=self.page
return await page.cookies()
async def getCookieStr(page):
if page==None:
page=self.page
cookies_list=await page.cookies()
cookies=''
for cookie in cookies_list:
str_cookie='{0}={1};'
str_cookie=str_cookie.format(cookie.get('name'), cookie.get('value'))
cookies +=str_cookie
try:print(cookies)
except:pass
return cookies
async def setCookies(self, page, cookies):
if page==None:
page=self.page
return await page.setCookie(*cookies)
async def getHtml(self, page):
if page==None:
page=self.page
return (await page.content())
async def getCurPageTitle(self, page):
if page==None:
page=self.page
return (await page.title())
async def getElementFieldValue(self, page, element, field):
if element==None:
print("當前傳入的【element】不能為空,參數(shù)錯誤!!")
return None
if field==None:
print("當前傳入的【field】不能為空,參數(shù)錯誤!!")
return None
if page==None:
page=self.page
if str(type(element))=="<class 'list'>":
print("當前傳入的【element】不是單個對象,為list集合,參數(shù)錯誤!!")
return None
fieldValue=(await element.getProperty(field)).jsonValue()
return fieldValue
async def getPageWidthHight(self, page):
if page==None:
page=self.page
return await page.evaluate('''()=> {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio,
}
}''')
async def getCurBrowserAllPages(self):
return await self.browser.pages()
async def getElementsByXpaths(self, page, xpath:'如://div[@class="title-box"]/a'):
if xpath==None:
print("當前傳入的【xpath】不能為空,參數(shù)錯誤!!")
return None
if page==None:
page=self.page
try:elemList=await page.xpath(xpath)
except:
print("獲取xpath路徑為【" + str(xpath) + "】的標簽對象異常...")
return elemList#返回類型為:list集合;
async def getPageText(self, page):
if page==None:
page=self.page
'''Pyppeteer的evaluate()方法只使用JavaScript字符串,該字符串可以是函數(shù)也可以是表達式,
Pyppeteer會進行自動判斷。但有時會判斷錯誤,如果字符串被判斷成了函數(shù),并且報錯,
可以添加選項force_expr=True,強制Pyppeteer作為表達式處理。'''
return await page.evaluate('document.body.textContent', force_expr=True)
async def getElementText(self, page, element):
if element==None:
print("當前傳入的【element】不能為空,參數(shù)錯誤!!")
return None
if page==None:
page=self.page
if str(type(element))=="<class 'list'>":
print("當前傳入的【element】不是單個對象,為list集合,參數(shù)錯誤!!")
return None
return await page.evaluate('(element)=> element.textContent', element)
async def getElementBySelector(self, page , selector):
if selector==None:
print("當前傳入的【selector】不能為空,參數(shù)錯誤!!")
return None
if page==None:
page=self.page
return await page.querySelector(selector)
async def inputKw(self, page, selector:"如:'input#kw.s_ipt':獲取input標簽中id='kw',class='s_ipt'的對象。不可用xpath路徑", kw:'待輸入的關鍵詞'):
if kw==None:
return None
if selector==None:
return None
if page==None:
page=self.page
try:print(selector, kw)
except:pass
await page.type(selector, kw)
return None
async def clickElement(self, page, selector:"如:'input#kw.s_ipt':獲取input標簽中id='kw',class='s_ipt'的對象。。不可用xpath路徑"):
if selector==None:
print("當前傳入的【selector】不能為空,參數(shù)錯誤!!")
if page==None:
page=self.page
await page.click(selector)#如果selector獲取的對象是list集合,則執(zhí)行第一個元素的點擊;
async def removeInputValue(self, page, idValue):
if idValue==None:
print("當前傳入的【idValue】不能為空,參數(shù)錯誤!!")
if page==None:
page=self.page
await page.evaluate("document.querySelector('#" + str(idValue) + "').value=''")
print("清空【" + str(idValue) + "】的內容")
async def clickByEle(self, ele):
if ele==None:
return
return await ele.click()
async def getLastPage(self):
pages=await self.browser.pages()
return pages[-1]
async def getPageTotal(self):
pages=await self.browser.pages()
return len(pages)
async def getFirstPage(self):
pages=await self.browser.pages()
return pages[0]
async def getAllFrames(self, page):
if page==None:
page=self.page
return await page.frames
async def getScreenshotByEle(self, page, ele, screenshotFilePath:"目前測試只有.png圖片可正常生成,jpg異常;"):
picture=''
try:
fu=File_Utils(None)
fu=File_Utils(fu.getParentDir(screenshotFilePath))
if not fu.exists(fu.getParentDir(screenshotFilePath)):fu.makeDirs()#如果圖片的保存目錄不存在,則創(chuàng)建;
time.sleep(3)
try:
for _ in range(6):
clip=await ele.boundingBox()
picture=base64.b64encode(await page.screenshot({
'path': screenshotFilePath, # 圖片路徑, 不指定就不保存
'clip': clip # 指定圖片位置,大小
}))
if picture !='':
break
except Exception as e:
print(traceback.print_exc())
except Exception as e:
print(traceback.print_exc())
return picture
注意事項:
測試過程中發(fā)現(xiàn),基于PC端的登錄界面,在Pyppeteer瀏覽器中,登錄按鈕無法使用。但是手機端登錄界面可以正常登錄
午已經(jīng)說完了CSS文本樣式,接著說下CSS的引入方式,包含內部樣式表(嵌入式),行內樣式表(行內式)和外部樣式表(鏈接式)。
內部樣式表(內嵌樣式表)是寫道HTML頁面內部,是將所有的CSS代碼抽取出來,單獨放到一個<style>?標簽中。
以前的語法展示:
<style>
? ?div {
? ?color:pink;
font-size:12px;
?}
</style>
將所有的樣式,都放到<style>標簽中
展示如下:
對應的代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS引入方式-內部樣式表</title>
<!-- 將所有的樣式都放在一個<style>標簽中 -->
<style>
div {
/* 文本顏色屬性 */
color: blue;
/* 文本行間距 */
line-height: 32px;
/* 讓文本在中間展示 */
text-align: center;
}
p {
/* 段落首行收縮2個字 */
text-indent: 2em;
}
a {
/* 文本不展示下劃線 */
text-decoration: none;
}
</style>
</head>
<body>
<div>戰(zhàn)無不勝,攻無不克,橫刀立馬,千秋萬代</div>
<p>10月15日晚,甘肅省天水市婦女聯(lián)合會官方微博發(fā)布通報稱,經(jīng)過多方勸解,孩子父親毛某已于10月14日將孩子送到母親范某身邊。目前孩子健康狀況良好,范某情緒穩(wěn)定,毛某也認識到因自己一時沖動造成的嚴重后果,并保證不再有過激行為。</p>
<div>一片祥云,我自橫刀向天笑</div>
<!-- 下劃線展示 -->
文本不展示下劃線<br/>
<a href="www.baidu.com">跳轉到百度頁面</a>
</body>
</html>
<style>標簽理論上可以放到HTML文檔的任何地方,但一般會放在文檔的<head>?標簽中。通過此種方式,可以方便控制當前整個頁面中的?元素樣式設置。代碼結構非常清晰,但是并沒有實現(xiàn)?結構與樣式完全分離。使用內部樣式設定CSS,通常也被成為嵌入式引入,?這種方式是我們練習時的常用方式。
我向您講授了如何向 html 頁面添加 JavaScript,使得網(wǎng)站的動態(tài)性和交互性更強。
你已經(jīng)學習了如何創(chuàng)建對事件的響應,驗證表單,以及如何根據(jù)不同的情況運行不同的腳本。
你也學到了如何創(chuàng)建和使用對象,以及如何使用 JavaScript 的內置對象。
如需更多關于 JavaScript 的信息和知識,請參閱我的 JavaScript 實例 和 JavaScript 參考手冊。
現(xiàn)在已經(jīng)你已經(jīng)學習了 JavaScript,接下來該學習什么呢?
下一步應該學習 HTML DOM 和 DHTML。
如果你希望學習關于服務器端腳本的知識,那么下一步應該學習 ASP,PHP, .Net。
HTML DOM
HTML DOM 定義了訪問和操作 HTML 文檔的標準方法。 HTML DOM 獨立于平臺和語言,可被任何編程語言使用,比如 Java、JavaScript 和 VBscript。
jQuery
jQuery 是一個 JavaScript 庫。
jQuery 極大地簡化了 JavaScript 編程。
jQuery 很容易學習。
AJAX
AJAX=異步 JavaScript 和 XML。
AJAX 不是一種新的編程語言,而是一種使用現(xiàn)有標準的新方法。
通過與服務器進行數(shù)據(jù)交換,AJAX 可以在不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進行更新。
有很多使用 AJAX 的應用程序案例:新浪微博、Google 地圖、開心網(wǎng)等等。
ASP / PHP / .NET
和 HTML 文檔中的腳本運行于客戶端(瀏覽器)不同,ASP/PHP 文件中的腳本在服務器上運行。
使用 ASP,你可以動態(tài)地編輯、改變或者添加網(wǎng)站內容,對由 HTML 表單提交而來的數(shù)據(jù)進行響應,訪問數(shù)據(jù)或者數(shù)據(jù)庫并向瀏覽器返回結果,或者定制對不同的用戶來說更有幫助的網(wǎng)頁。
由于 ASP/PHP 文件返回的是純粹的 HTML,因此可顯示在任何瀏覽器中。
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。