當前位置:成語大全網 - 書法字典 - Python字典拼接url

Python字典拼接url

0x00。原因

因為參加大學生創新大賽,研究微博博文所表達的情感,需要大量的微博博文,而無論是國內的某度、csdn,還是國外的Google、gayhub、codeproject,都找不到想要的程序,只好自己寫程序。

贊美詩我在《攀登聯盟》中發現了壹個類似的程序,但它是在windows下運行的,並且源代碼是關閉的。而且,在爬取保存的文件並用notepad++打開它時出現了許多奇怪的問題,所以我放棄了。

0x001。基礎知識

這個程序是由python編寫的,因此基本的Python知識是必要的。另外,如果妳有壹定的計算機網絡基礎,妳會在前期準備中走很多彎路。

對於爬行動物,妳需要清楚以下幾點:

1.爬取對象的分類可以分為以下幾類:第壹類是不需要登錄的,比如博主練手時爬取的中國天氣網。這類網頁很難爬取,建議爬蟲新手爬這類網頁;二是登錄,如豆瓣、新浪微博等難爬的;第三類獨立於前兩類,您想要的信息通常是動態刷新的,例如AJAX或嵌入式資源。這種爬蟲是最難的,博主也沒研究過,這裏就不細說了(據同學說淘寶的商品評論都屬於這壹類)。

2.如果同壹個數據源有多種形式(如電腦版、移動版、客戶端等。),呈現方式越“純粹”越好。比如新浪微博有網頁版和手機版,手機版可以通過電腦瀏覽器訪問。這個時候我更喜歡手機版的新浪微博。

3.爬蟲通常將網頁下載到本地,然後通過某些方式提取有趣的信息。換句話說,抓取網頁只完成了壹半,您需要從下載的html文件中提取您感興趣的信息。此時,需要壹些xml知識。在這個項目中,博客作者使用XPath提取信息,也可以使用XQuery等其他技術。詳情請訪問w3cschool。

4.爬蟲應該盡可能模仿人類。現在網站的反抓取機制已經開發出來了。從驗證碼到IP封禁,爬蟲技術和反爬蟲技術可謂博弈不斷。

0x02。去

確定爬蟲的目標後,首先應該訪問目標網頁,找出目標網頁屬於上述哪種爬蟲。此外,記錄為了獲得感興趣的信息而需要采取的步驟,例如是否需要登錄,如果需要登錄,是否需要驗證碼;妳需要做什麽來獲得妳想要的信息,妳是否需要提交壹些表格;您想要獲取信息的頁面的url的規則是什麽,等等。

以下博客文章以blogger項目為例。該項目抓取特定新浪微博用戶自註冊以來的所有微博博文,並根據關鍵詞抓取100頁微博博文(約1000篇帖子)。

0x03。收集必要的信息

首先,訪問目標網頁並發現您需要登錄。進入登錄頁面如下:新浪微博手機版登錄頁面。

請註意,在url的後半部分有許多像“%xx”這樣的轉義字符,這將在本文稍後討論。

從這個頁面可以看到,登錄新浪微博手機版需要填寫賬號、密碼和驗證碼。

這個驗證碼只需要在最近提供(本文創建於2016.3.11)。如果不需要提供驗證碼,將有兩種登錄方式。

第壹種方法是進行js模擬,填寫賬戶密碼後點擊“登錄”按鈕。博主之前用這個方法寫了壹個Java爬蟲,現在找不到項目了,這裏就不贅述了。

第二種類型需要壹定的HTTP基礎,並提交包含所需信息的HTTP POST請求。我們需要Wireshark工具來捕獲登錄微博時發送和接收的數據包。如下圖所示,我抓取了登錄時發送和接收的數據包。Wireshark抓取了1的結果。

在搜索欄“/(display id)中提供搜索條件?page =(pagenum)。這將是我們的爬蟲拼接url的基礎。

接下來,查看網頁的源代碼並找到我們想要的信息的位置。打開瀏覽器開發者工具,直接定位壹個微博,就能找到它的位置,如下圖。

xpath

觀察html代碼,發現所有微博都在《div & gt標簽,這個標簽中有兩個屬性,其中class屬性是“c”和壹個唯壹的id屬性值。獲取這些信息有助於提取所需的信息。

此外,還有壹些因素需要特別註意。

*微博分為原創微博和轉發微博。

*根據發布時間與當前時間的差異,頁面上顯示時間的方式有多種,例如“MM分鐘前”、“今天的HH:MM”、“MM月dd日HH:MM-DD hh: mm: SS”。*手機版新浪微博的壹頁顯示大約65,438+00條微博,因此請註意總數* *。

0x04。編碼

1.抓取用戶微博

這個項目的開發語言是Python 2.7,項目中使用了壹些第三方庫,可以通過pip添加。

由於驗證碼阻止了自動登錄的想法,用戶只有在想要訪問特定用戶的微博頁面時才能提供cookies。

第壹個是Python的請求模塊,它為url請求提供cookies。

導入請求

打印請求。get(URL,cookies = cookies)。內容使用此代碼打印帶有cookies的URL請求頁面結果。

首先,獲取用戶的微博頁面數量。通過檢查網頁的源代碼,找到代表頁數的元素,並通過XPath等技術提取頁數。

頁數

該項目使用lxml模塊通過XPath提取html。

首先,導入lxml模塊,項目中僅使用etree,因此從lxml導入etree。

然後使用下面的方法返回頁碼。

def getpagenum(self):

URL = self . geturl(pagenum = 1)

html = requests . get(URL,cookies = self.cook)。內容#訪問第壹頁獲取頁碼。

選擇器= etree。HTML(HTML)

pagenum = selector . XPath(‘//input【@ name =“MP“】/@ value‘‘)【0】

return int(pagenum)

下壹步是連續拼接url-》訪問URL-& gt;下載網頁。

需要註意的是,由於新浪反抓取機制的存在,如果相同的cookies訪問頁面過於頻繁,它將進入類似的“冷靜期”,即它將返回壹個無用的頁面。通過分析這個無用的頁面,發現這個頁面在特定的地方會有特定的信息,而這個頁面對我們是否有用可以通過XPath技術來判斷。

def ispageneeded(html):

選擇器= etree。HTML(HTML)

嘗試:

title = selector . XPath(‘//title‘‘)【0】

除了:

返回False

返回title.text!=‘微博廣場’和title.text!=‘微博‘

如果有無用的頁面,您只需要再次訪問它們。但是,通過後來的實驗發現,如果長時間頻繁訪問它們,返回的所有頁面都將是無用的,程序將陷入無限循環。為了防止程序陷入無限循環,博主設置了壹個trycount閾值,超過該閾值後該方法將自動返回。

下面的代碼片段顯示了單線程爬蟲的方法。

def開始搜索(self,startpage=1,trycount=20):

嘗試= 0

嘗試:

OS . mkdir(sys . path【0】+‘/Weibo _ raw/‘+self . wanted)Exception,e:

打印字符串(e)

isdone = False

而不是isdone並嘗試& lt嘗試計數:

嘗試:

pagenum = self.getpagenum()

isdone = True

除了例外,e:

嘗試+= 1

if attempt == trycount:

返回False

i =起始頁

當我& lt= pagenum:

嘗試= 0

isneeded = False

html =‘‘‘

當不需要和嘗試& lt嘗試計數:

html = self . getpage(self . geturl(I))

isneeded = self . ispageneeded(html)

如果不需要:

嘗試+= 1

if attempt == trycount:

返回False

self . save html(sys . path【0】+‘/Weibo _ raw/‘+self . wanted+‘/‘+str(I)+‘。txt,html)打印字符串(I)+‘/‘+字符串(pagenum - 1)

i += 1

返回True

考慮到程序的時間效率,在編寫了單線程爬蟲之後,該博主還編寫了多線程爬蟲版本。基本思路是用微博頁面數除以線程數。例如,如果微博中的用戶有65,438+000個微博頁面,程序有65,438+00個線程,那麽每個線程只負責爬取65,438+00個頁面。其他基本思想與單線程類似,只有邊界值需要仔細處理,因此我在此不再贅述。另外,由於多線程的效率比較高,並發量特別大,服務器很容易返回無效頁面,所以trycount的設置比較重要。這位博主在寫這條微博時,用了壹個新的cookie來測試誰爬上了北京郵電大學的微博。3976篇微博文章全部成功爬取,並提取了博文。只花了15s,這實際上可能與新舊cookies和網絡環境有關。命令行設置如下,項目網站中解釋了命令行的含義:python main.py _ T _ WM = xxxSUHB = xxxSUB = xxxGSID _ CTANDWM = XXX UBUPPT M 20 20以上關於爬蟲的基本介紹工作就結束了,接下來分析爬蟲的第二部分。因為項目提供了多線程抓取方法,而多線程壹般是亂序的,但微博的博文是按時間排序的,所以項目采用了壹種折中的方法,將下載的頁面保存在本地文件系統中,每個頁面以其頁碼作為文件名。爬行工作完成後,將遍歷並解析文件夾中的所有文件。

通過前面的觀察,我們了解到了微博的博文都有哪些特點。通過使用XPath技術,從該頁面中提取具有該特性的所有標簽並不困難。

再次,微博分為轉發微博和原創微博,以及時間表達。此外,由於我們的研究主題只對微博文本感興趣,因此我們不考慮插圖。

def start parsing(self,parsing time = datetime . datetime . now()):

basepath = sys . path【0】+‘/Weibo _ raw/‘+self . uid for filename in OS . listdir(basepath):

if filename . starts with(‘。‘):

繼續

path = base path+‘/‘+文件名

f =打開(路徑,‘r‘)

html = f.read()

選擇器= etree。HTML(HTML)

weiboitems = selector . XPath(‘//div【@ class =“c“】【@ id】‘)用於Weibo items中的項目:

微博=微博()

weibo.id = item.xpath(。/@ id’)【0】

cmt = item.xpath(。/div/span【@ class =“CMT“】‘)if len(CMT)!= 0:

Weibo . is post = True

Weibo . content = CMT【0】。文本

否則:

weibo.isrepost = False

ctt = item.xpath(。/div/span【@ class =“CTT“】‘)【0】

如果ctt.text不為None:

微博內容+= ctt.text

對於ctt.xpath(。/a’):

如果a.text不為None:

微博內容+= a.text

如果a.tail不為None:

weibo.content += a .尾巴

if len(CMT)!= 0:

reason = CMT【1】。text。split(u‘\ xa0‘)

if len(原因)!= 1:

Weibo . reports on = reason【0】

ct = item.xpath(。/div/span【@ class =“CT“】‘)【0】

time = CT . text . split(u‘\ xa0‘‘【0】

Weibo . time = self . gettime(self,time,parsing time)self . weibos . append(Weibo。__dict__)

關閉()

方法傳遞的參數parsingtime設置的初衷是在開發初期可能不會同時進行抓取和解析(並非嚴格意義上的“同時”),而微博時間顯示是根據訪問時間進行的,例如抓取時間為10:00,5分鐘前發布了壹條微博顯示,但如果解析時間為10:30,解析時間就會出錯,所以。到爬蟲基本發育結束時,爬行和解析的開始時間差距就會縮小,時間差就是爬行過程的時間,基本可以忽略。

解析結果保存在列表中。最後,列表以json格式保存到文件系統中,並刪除過渡文件夾。

定義保存(自身):

f = open(sys . path【0】+‘/Weibo _ parsed/‘+self . uid+‘。txt,‘w‘)jsonstr = JSON . dumps(self . weibos,indent=4,確保_ ascii = False)f . write(jsonstr)

關閉()

抓取關鍵詞

同樣,收集必要的信息。在微博手機搜索頁面輸入“python”,觀察網址,研究其規律。雖然第壹頁上沒有規則,但我們在第二頁上發現了壹條規則,並且這條規則可以應用回第壹頁。

第二頁

申請後的第壹頁

觀察url,我們可以發現url中唯壹的變量是關鍵字和頁面(實際上,hideSearchFrame對我們的搜索結果和爬蟲沒有任何影響),因此我們可以在代碼中控制這兩個變量。

此外,如果關鍵字是中文,那麽url需要轉換漢字。例如,如果我們在搜索框中鍵入“Happy”並進行搜索,我們會發現url顯示Happy Search如下。

但是它被復制為

/search/mblog?hideSearchFrame = & amp關鍵字= % E5 % BC % 80 % E5 % BF % 83 & ampPage=1幸運的是,python的urllib庫具有qoute方法處理中文轉換的功能(如果是英文,則不會轉換),因此在拼接URL之前使用此方法處理參數。

此外,考慮到關鍵字搜索屬於數據收集階段使用的方法,我們在此僅提供網頁的單線程下載。如果有多線程的需求,可以按照多線程抓取用戶微博的方法自己重寫。最後,提取並保存下載的網頁(我知道這個模塊設計有點奇怪,所以我打算在我想重新創建它時更改它(hao),所以我們就這樣做吧)。

def關鍵字爬網(自身,關鍵字):

real keyword = urllib . quote(keyword)#用中文處理關鍵字。

嘗試:

OS . mkdir(sys . path【0】+‘/keywords‘)

除了例外,e:

打印字符串(e)

微博=【】

嘗試:

high points = re . compile(u‘【\ u 00010000-\ u 0010 ffff】‘)#處理表情符號,但似乎不起作用。

除了re.error:

high points = re . compile(u‘【\ ud 800-\ uDBFF】【\ UDC 00-\ uDFFF】‘)pagenum = 0

isneeded = False

不需要時:

html = self . get page(‘/search/mblog?關鍵字= % s & amppage = 1“% real keyword)is needed = self . ispageneeded(html)

如果需要:

選擇器= etree。HTML(HTML)

嘗試:

pagenum = int(selector . XPath‘//input【@ name =“MP“】/@ value‘‘【0】),以下情況除外:

pagenum = 1

對於範圍內的I(1,pagenum + 1):

嘗試:

isneeded = False

不需要時:

html = self . get page(‘/search/mblog?關鍵字= % s & amppage = % s“%(real keyword,str(I))is needed = self . ispageneeded(html)

選擇器= etree。HTML(HTML)

weiboitems = selector . XPath(‘//div【@ class =“c“】【@ id】‘)用於Weibo items中的項目:

cmt = item.xpath(。/div/span【@ class =“CMT“】‘)if(len(CMT))= = 0:

ctt = item.xpath(。/div/span【@ class =“CTT“】‘)【0】

如果ctt.text不為None:

text = etree . tostring(CTT,method =‘text‘,encoding =“unicode“)tail = CTT . tail

if text . ends with(tail):

index =-len(tail)

text = text【1:index】

text = high points . sub(u‘\ u25FD‘,text)#表情符號的處理方式似乎不起作用。

weibotext =文本

微博附加(微博文本)

打印字符串(I)+‘/‘+字符串(pagenum)

除了例外,e:

打印字符串(e)

f = open(sys . path【0】+‘/keywords/‘+keyword+‘。txt,‘w’)嘗試:

f . write(JSON . dumps(weibos,indent=4,確保_ ascii = False))Exception除外,例如:

打印字符串(ex)

最後:

關閉()

博客作者以前從未編寫過任何爬蟲程序。為了獲得新浪微博的博文,博主們編寫了三種不同的爬蟲程序,包括Python和Java。爬行動物不能用是正常的。不要氣餒。爬蟲程序和反爬行機制壹直在不停地玩遊戲。

另外,轉載請告知博主,認為博是老板的不需要告知。