Python爬虫与信息提取(五)爬虫实例:爬取新浪微博热搜排名
經(jīng)過一段時間的Python網(wǎng)絡(luò)爬蟲學習,今天自己摸索制作了一個能夠爬取新浪微博實時熱搜排名的小爬蟲
1.效果:
2.制作過程中遇到的問題:
(1)一開始研究微博熱搜頁面的源代碼時忽略了<tbody>中還包括一個置頂熱搜,它的標簽包含結(jié)構(gòu)和其他的50個不同,因此需要單獨考慮
(2)難點是標簽中信息的獲取,需要搞清楚 find_all( ) 函數(shù)返回的是列表,只能用于for遍歷體系中,針對HTML中的<tbody>下面的<tr>節(jié)點,<tr>下面的<tb>子節(jié)點,都需要一步一步地find到
(3)在一開始不知道如何使用class="td-01"屬性直接find到內(nèi)容,因為python的關(guān)鍵字class會和class=發(fā)生重名的情況,經(jīng)過查閱之后發(fā)現(xiàn),可以使用 class_ 代替 class
https://blog.csdn.net/IMW_MG/article/details/78109199
(4)在獲取的時候曾經(jīng)遇到了問題:使用<>.string獲取不到標簽中的字符串內(nèi)容,這種情況會在熱搜排名中帶有表情emoji時發(fā)生,經(jīng)過調(diào)試得到了將string替換為text的解決方法,可以正常地得到字符串的內(nèi)容
(5)正確地獲取到一個存儲信息的二維列表之后,還需要按照格式從而正確地打印出來,這又是一個難點。一直遇到了一個問題:在中英混合的字符串中,內(nèi)置的len( )函數(shù)無法正確地計算字符串的字符長度(不是長度!),從而導(dǎo)致了輸出排版不整齊的問題。經(jīng)過查閱之后,有下面的內(nèi)容解決了這樣的問題:
https://www.jb51.net/article/86577.htm
?于是內(nèi)建了函數(shù)length( )來正確獲取字符串的字符寬度,從而正確計算所需空格的數(shù)量
#獲取一個中英文混合的字符串文本的字符寬度部分 widths = [(126, 1), (159, 0), (687, 1), (710, 0), (711, 1),(727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),(4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1),(8426, 0), (9000, 1), (9002, 2), (11021, 1), (12350, 2),(12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1),(55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),(65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),(120831, 1), (262141, 2), (1114109, 1), ] def get_width(a):global widthsif a == 0xe or a == 0xf:return 0for num, wid in widths:if a <= num:return widreturn 1 def length(str):sum = 0for ch in str:sum += get_width(ord(ch))return sum3.全部代碼
import requests import re import bs4#獲取一個中英文混合的字符串文本的字符寬度部分 widths = [(126, 1), (159, 0), (687, 1), (710, 0), (711, 1),(727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),(4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1),(8426, 0), (9000, 1), (9002, 2), (11021, 1), (12350, 2),(12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1),(55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),(65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),(120831, 1), (262141, 2), (1114109, 1), ] def get_width(a):global widthsif a == 0xe or a == 0xf:return 0for num, wid in widths:if a <= num:return widreturn 1 def length(str):sum = 0for ch in str:sum += get_width(ord(ch))return sum#獲取HTML文本 def getHTMLText(url):try:#模擬瀏覽器kv = {'user-agent':'Mozilla/5.0'}r = requests.get(url, headers=kv, timeout=30) r.raise_for_status()r.encoding = r.apparent_encodingreturn r.textexcept:print("InternetError!")return " "#解析并且返回HTML文本 def HTMLTextconvert(html):try:soup = bs4.BeautifulSoup(html, "html.parser")return soupexcept:print("HTMLConvertError!")return " "#檢索HTML中的信息,獲取搜索排名信息 #存在置頂?shù)那闆r,需要特殊判斷 def HTMLSearch(html, ranklist):try:flag = 0#找到所有tbody標簽下的所有內(nèi)容,并且遍歷所有的兒子節(jié)點for tr in html.find("tbody").children:#添加判斷:獲得的內(nèi)容是否為標簽Tag類型if isinstance(tr, bs4.element.Tag):#使用flag特判置頂?shù)那闆rif flag==0:rank = "置頂"#注意由于class屬性會和python中的關(guān)鍵字重名,因此需要變?yōu)閏lass_td02 = tr.find_all(class_=re.compile('td-02'))for i in td02:if isinstance(i, bs4.element.Tag):#trans得到的類型為列表trans = i.find_all("a")number = " "ranklist.append([rank, trans[0].string, number])flag = 1else:#排名信息在td標簽下的class=td-01屬性中td01 = tr.find_all(class_=re.compile("td-01"))for i in td01:if isinstance(i, bs4.element.Tag):rank = i.string#熱搜內(nèi)容和搜索量在td標簽下的class=td-02屬性中:內(nèi)容是a標簽,搜索量是span標簽td02 = tr.find_all(class_=re.compile("td-02"))for i in td02:name = i.find_all("a")column = i.find_all("span")#使用string獲取字符串信息不準確,因為微博還有一些熱搜標題為含有表情的,因此使用了textranklist.append([rank, name[0].text, column[0].text])except:print("HTMLSearchError!")#打印排名 def Rankprint(ranklist, num):try:#先打印表頭,總長為70個字符,其中{1}和{3}是變化的空格數(shù)量計算,默認為:#排名*4,空格*3,名稱*50,空格*5,點擊量*8a = " "print("——————————————————————————————————————")print("{0}{1}{2}{3}{4}\n".format("排名", a*5, "熱搜內(nèi)容", a*45, "搜索量"+a*2))#使用flag來判斷是否輸出了置頂內(nèi)容flag = 0for i in range(num):if flag==0:print("{0}{1}{2}\n".format(ranklist[i][0], a*3, ranklist[i][1]))flag = 1else:#c是排名有一位、兩位的數(shù)字,用來糾正空格c = 7-len(ranklist[i][0])#根據(jù)內(nèi)容來隨時計算所要填充的空格數(shù)量bstr = ranklist[i][1]b = 62-length(ranklist[i][1])-len(ranklist[i][0])-cprint("{0}{1}{2}{3}{4:<8}".format(ranklist[i][0], a*c, ranklist[i][1], a*b, ranklist[i][2]))print("\n")except:print("RankPrintError!")#主函數(shù) def main():try:#微博熱搜的網(wǎng)站url = "https://s.weibo.com/top/summary?Refer=top_hot&topnav=1&wvr=6"#使用二維列表存儲每一條熱搜信息的rank信息和內(nèi)容rank = []text = getHTMLText(url)soup = HTMLTextconvert(text)HTMLSearch(soup, rank)Rankprint(rank, 51)except:print("SystemError!")return 0 main()在所有可能發(fā)生錯誤的部分都增加了報錯機制,這樣程序就更加的具有適應(yīng)能力了!
?
總結(jié)
以上是生活随笔為你收集整理的Python爬虫与信息提取(五)爬虫实例:爬取新浪微博热搜排名的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: A Swift Tour, 苹果新推出的
- 下一篇: 最近很多人问我:saiku下载不下来