Python爬虫与信息提取(五)爬虫实例:爬取新浪微博热搜排名
經過一段時間的Python網絡爬蟲學習,今天自己摸索制作了一個能夠爬取新浪微博實時熱搜排名的小爬蟲
1.效果:
2.制作過程中遇到的問題:
(1)一開始研究微博熱搜頁面的源代碼時忽略了<tbody>中還包括一個置頂熱搜,它的標簽包含結構和其他的50個不同,因此需要單獨考慮
(2)難點是標簽中信息的獲取,需要搞清楚 find_all( ) 函數返回的是列表,只能用于for遍歷體系中,針對HTML中的<tbody>下面的<tr>節點,<tr>下面的<tb>子節點,都需要一步一步地find到
(3)在一開始不知道如何使用class="td-01"屬性直接find到內容,因為python的關鍵字class會和class=發生重名的情況,經過查閱之后發現,可以使用 class_ 代替 class
https://blog.csdn.net/IMW_MG/article/details/78109199
(4)在獲取的時候曾經遇到了問題:使用<>.string獲取不到標簽中的字符串內容,這種情況會在熱搜排名中帶有表情emoji時發生,經過調試得到了將string替換為text的解決方法,可以正常地得到字符串的內容
(5)正確地獲取到一個存儲信息的二維列表之后,還需要按照格式從而正確地打印出來,這又是一個難點。一直遇到了一個問題:在中英混合的字符串中,內置的len( )函數無法正確地計算字符串的字符長度(不是長度!),從而導致了輸出排版不整齊的問題。經過查閱之后,有下面的內容解決了這樣的問題:
https://www.jb51.net/article/86577.htm
?于是內建了函數length( )來正確獲取字符串的字符寬度,從而正確計算所需空格的數量
#獲取一個中英文混合的字符串文本的字符寬度部分 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中的信息,獲取搜索排名信息 #存在置頂的情況,需要特殊判斷 def HTMLSearch(html, ranklist):try:flag = 0#找到所有tbody標簽下的所有內容,并且遍歷所有的兒子節點for tr in html.find("tbody").children:#添加判斷:獲得的內容是否為標簽Tag類型if isinstance(tr, bs4.element.Tag):#使用flag特判置頂的情況if flag==0:rank = "置頂"#注意由于class屬性會和python中的關鍵字重名,因此需要變為class_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#熱搜內容和搜索量在td標簽下的class=td-02屬性中:內容是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}是變化的空格數量計算,默認為:#排名*4,空格*3,名稱*50,空格*5,點擊量*8a = " "print("——————————————————————————————————————")print("{0}{1}{2}{3}{4}\n".format("排名", a*5, "熱搜內容", a*45, "搜索量"+a*2))#使用flag來判斷是否輸出了置頂內容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是排名有一位、兩位的數字,用來糾正空格c = 7-len(ranklist[i][0])#根據內容來隨時計算所要填充的空格數量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!")#主函數 def main():try:#微博熱搜的網站url = "https://s.weibo.com/top/summary?Refer=top_hot&topnav=1&wvr=6"#使用二維列表存儲每一條熱搜信息的rank信息和內容rank = []text = getHTMLText(url)soup = HTMLTextconvert(text)HTMLSearch(soup, rank)Rankprint(rank, 51)except:print("SystemError!")return 0 main()在所有可能發生錯誤的部分都增加了報錯機制,這樣程序就更加的具有適應能力了!
?
總結
以上是生活随笔為你收集整理的Python爬虫与信息提取(五)爬虫实例:爬取新浪微博热搜排名的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: A Swift Tour, 苹果新推出的
- 下一篇: 最近很多人问我:saiku下载不下来