1. 程式人生 > >Python 利用 BeautifulSoup 爬取網站獲取新聞流

Python 利用 BeautifulSoup 爬取網站獲取新聞流

lxml odi creat times 對比 文件中 lse win 危機

0. 引言

  介紹下 Python 用 Beautiful Soup 周期性爬取 xxx 網站獲取新聞流;

技術分享圖片

圖 1 項目介紹

1. 開發環境

  Python:      3.6.3

  BeautifulSoup:   4.2.0 , 是一個可以從HTML或XML文件中提取數據的Python庫*

  ( BeautifulSoup 的中文官方文檔:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ )

2. 代碼介紹

實現主要分為三個模塊:

  1. 計時 / second cnt

    因為是周期性爬取,所以需要計時器來控制;

  2. 設置代理 / set proxy

    為了應對網站的反爬蟲機制,需要切換代理;

  3. 爬蟲 / web spider

    利用 requests 請求網站內容,然後 beautifulsoup 提取出所需信息;

利用 requests.get() 向服務器發送請求 >>> 拿到 html 內容 >>> 交由 beautifulsoup 用來解析提取數據;

先看一個 requests 和 beautifulsoup 拿數據的簡單例子:

requests 發送請求給網站,然後 get 到返回的 html,然後再轉換為 beautifulsoup 的對象;

( headers 和 proxies 是可選項 / optional )

 1 from bs4 import BeautifulSoup
 2 import requests
 3 html = "https://www.xxx.com"
 4 headers = {
 5     User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
 6 }
 7 proxies = "114.231.xx.xx:xxxx
" 8 9 resp = requests.get(html, headers=headers, proxies=proxies) 10 resp.encoding = utf-8 11 12 bsObj = BeautifulSoup(resp.content, "lxml")

本文以爬取 https://www.ithome.com/blog/ 為例,把頁面上的新聞爬取下來,過濾掉多余信息,拿到 新聞時間 & 新聞標題

技術分享圖片

圖 2 網站界面

拿到網站的 html 代碼之後,如何剝離出自己想要的數據,參考圖 3 的流程:

技術分享圖片

  圖 3 從 html 中 剝離數據的流程

首先看看 bsObj = BeautifulSoup(resp.content, "lxml") 拿到的 目標網站 ( https://www.ithome.com/blog/ ) 的 HTML 代碼:

...
<
div class="block"> <h2> <a href="https://www.ithome.com/html/android/380353.htm" target="_blank">魅族黃章評價滑蓋智能手機:窮途末路倒退的設計,中看不中用</a><span class="state tody">今日 14:53</span></h2> <div class="memo"> <p>昨晚榮耀Magic2、小米MIX 3手機相繼亮相,並且都采用了升降式或者滑蓋式屏幕設計。剛剛魅族黃章對於滑蓋設計表達了自己的看法:滑蓋可以說是窮途末路倒退的設計。</p> </div> </div> </li> <li> <a class="list_thumbnail" href="https://www.ithome.com/html/discovery/380352.htm" target="_blank"> <img src="//img.ithome.com/newsuploadfiles/thumbnail/2018/8/380352_240.jpg"/> </a> <div class="block"> <h2> <a href="https://www.ithome.com/html/discovery/380352.htm" target="_blank">俄羅斯計劃“世界級”研究中心,擬克隆猛獁象</a><span class="state tody">今日 14:48</span></h2> <div class="memo"> <p>俄羅斯科學家計劃用保存的冰河時代遺骸的DNA,在一個耗資450萬英鎊的新侏羅紀公園中心克隆猛獁象</p> </div> </div> </li> <li> <a class="list_thumbnail" href="https://lapin.ithome.com/html/digi/380351.htm" target="_blank"> <img src="//img.ithome.com/newsuploadfiles/thumbnail/2018/8/380351_240.jpg"/> </a> <div class="block"> <h2>
...

需要一層層剝出數據,首先定位到 <div class="block" >;

>>> block = bsObj.find_all("div", {"class": "block"})
<div class="block">
  <h2>
    <a href="https://www.ithome.com/html/android/380353.htm" target="_blank"> 魅族黃章評價滑蓋智能手機:窮途末路倒退的設計,中看不中用</a>
    <
span class="state tody">今日 14:53</span>
  </
h2> <div class="memo">   <p>昨晚榮耀Magic2、小米MIX 3手機相繼亮相,並且都采用了升降式或者滑蓋式屏幕設計。剛剛魅族黃章對於滑蓋設計表達了自己的看法:滑蓋可以說是窮途末路倒退的設計。</p> </div>

接下來就是要提取出 新聞標題 title 和 新聞時間 time;

對於單個的 block:

提取新聞時間:

>>> block.find(‘span‘, {‘class‘: "state tody"})
<span class="state tody">今日 14:53</span>

然後

>> block.find(‘span‘, {‘class‘: "state tody"}).get_text()

得到 time 內容:

今日 14:53


提取新聞標題:

>>> block[i].find(‘a‘, {‘target‘: "_blank"})
<a href="https://www.ithome.com/html/android/380353.htm" target="_blank">魅族黃章評價滑蓋智能手機:窮途末路倒退的設計,中看不中用</a>

然後

>> block.find(‘a‘, {‘target‘: "_blank"}).get_text()

得到 title 內容:

魅族黃章評價滑蓋智能手機:窮途末路倒退的設計,中看不中用

這樣就可以拿到了 新聞標題 titile 和 新聞時間 time了;

3. 代碼實現

1. 計時器

這裏是一個秒數計數功能模塊,利用 datetime 這個庫,獲取當前時間的秒位,和開始時間的秒位進行比對,如果發生變化,sec_cnt 就 +=1;

sec_cnt 輸出 1,2,3,4,5,6...是記錄的秒數,可以由此控制抓包時間;

>>> time = datetime.datetime.now()   # 獲取當前的時間,比如:2018-08-31 14:32:54.440831
>>> time.second()             # 獲取時間的秒位

second_cnt.py:

 1 # Author:   coneypo
 2 # Created:  08.31
 3 
 4 import datetime
 5 
 6 # 開始時間
 7 start_time = datetime.datetime.now()
 8 tmp = 0
 9 # 記錄的秒數
10 sec_cnt = 0
11 
12 while 1:
13     current_time = datetime.datetime.now()
14 
15     # second 是以60為周期
16     # 將開始時間的秒 second / 當前時間的秒 second 進行對比;
17     # 如果發生變化則 sec_cnt+=1;
18     if current_time.second >= start_time.second:
19         if tmp != current_time.second - start_time.second:
20             # print("<no 60>+  ", tmp)
21             sec_cnt += 1
22             print("Time_cnt:", sec_cnt)
23             # 以 10s 為周期
24             if sec_cnt % 10 == 0:
25                 # do something
26                 pass
27         tmp = current_time.second - start_time.second
28 
29     # when get 60
30     else:
31         if tmp != current_time.second + 60 - start_time.second:
32             sec_cnt += 1
33             print("Time_cnt:", sec_cnt)
34 
35             # 比如以 10s 為周期
36             if sec_cnt % 10 == 0:
37                 # do something
38                 pass
39         tmp = current_time.second + 60 - start_time.second

2. get_proxy / 獲取代理

這個網站可以提供一些國內的代理地址: http://www.xicidaili.com/nn/ ;

因為現在網站可能會有反爬蟲機制,如果同一個 IP 如果短時間內大量訪問該站點,就會被攔截;

所以我們需要設置代理,拿到的 proxy 地址傳給 requests.get 的 proxies 參數:

>>> requests.get(html, headers=headers, proxies=proxies)

get_proxy.py :

 1 # Author:   coneypo
 2 # Created:  08.31
 3 # set proxy
 4 
 5 from bs4 import BeautifulSoup
 6 import requests
 7 import random
 8 
 9 
10 def get_proxy():
11     headers = {
12         User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
13     }
14     proxy_url = http://www.xicidaili.com/nn/
15     resp = requests.get(proxy_url, headers=headers)
16     soup = BeautifulSoup(resp.text, lxml)
17     ips = soup.find_all(tr)
18     proxy_list = []
19 
20     for i in range(1, len(ips)):
21         ip_info = ips[i]
22         tds = ip_info.find_all(td)
23         proxy_list.append(tds[1].text + : + tds[2].text)
24 
25     proxy = proxy_list[random.randint(0, len(proxy_list))]
26 
27     print(proxy)
28     return proxy

3. get_news_from_xxx / 爬蟲

由計時器的 sec_cnt 控制爬蟲的周期,每次先去代理網站拿代理,然後交給 requests 去拿數據,拿到 HTML 之後交給 beautiful 對象,然後過濾出新聞流:

get_news_from_xxx.py 完整的代碼

  1 # Author:   coneypo
  2 # Created:  08.31
  3 # web spider for xxx.com
  4 
  5 from bs4 import BeautifulSoup
  6 import requests
  7 import random
  8 import datetime
  9 
 10 headers = {
 11     User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
 12 }
 13 
 14 
 15 # 設置代理
 16 def get_proxy():
 17     proxy_url = http://www.xicidaili.com/nn/
 18     resp = requests.get(proxy_url, headers=headers)
 19     soup = BeautifulSoup(resp.text, lxml)
 20     ips = soup.find_all(tr)
 21     proxy_list = []
 22 
 23     for i in range(1, len(ips)):
 24         ip_info = ips[i]
 25         tds = ip_info.find_all(td)
 26         proxy_list.append(tds[1].text + : + tds[2].text)
 27 
 28     proxy = proxy_list[random.randint(0, len(proxy_list))]
 29 
 30     print("Proxy:", proxy)
 31     return proxy
 32 
 33 
 34 # 爬取網站
 35 def get_news():
 36     html = "https://www.ithome.com/blog/"
 37     resp = requests.get(html, headers=headers, proxies=get_proxy())
 38     resp.encoding = utf-8
 39 
 40     # 網頁內容
 41     bsObj = BeautifulSoup(resp.content, "lxml")
 42     #print(bsObj)
 43 
 44     # 分析
 45     block = bsObj.find_all("div", {"class": "block"})
 46     #print(block)
 47 
 48     current_titles = []
 49     current_times = []
 50 
 51     # analysis every block
 52     for i in range(len(block)):
 53         # get Time
 54         time_classes = ["state tody", "state other"]
 55         for time_class in time_classes:
 56             tmp = block[i].find_all(span, {class: time_class})
 57             if tmp:
 58                 current_time = (block[i].find(span, {class: time_class})).get_text()
 59                 current_times.append(current_time)
 60 
 61         # get Title
 62         if block[i].find_all(a, {target: "_blank"}):
 63             current_title = (block[i].find(a, {target: "_blank"})).get_text()
 64             current_titles.append(current_title)
 65 
 66     for i in range(len(current_times)):
 67         print(current_times[i], current_titles[i])
 68     return current_times, current_titles
 69 
 70 get_news()
 71 
 72 # 計時
 73 start_time = datetime.datetime.now()
 74 tmp = 0
 75 sec_cnt = 0
 76 
 77 while 1:
 78     current_time = datetime.datetime.now()
 79 
 80     # second 是以60為周期
 81     # 將開始時間的秒second / 當前時間的秒second 進行對比
 82     if current_time.second >= start_time.second:
 83         if tmp != current_time.second - start_time.second:
 84             # print("<no 60>+  ", tmp)
 85             sec_cnt += 1
 86             print("Time_cnt:", sec_cnt)
 87             if sec_cnt % 10 == 0:
 88                 get_news()
 89                 print(\n)
 90         tmp = current_time.second - start_time.second
 91 
 92     # when get 60
 93     else:
 94         if tmp != current_time.second + 60 - start_time.second:
 95             sec_cnt += 1
 96             print("Time_cnt:", sec_cnt)
 97 
 98             if sec_cnt % 10 == 0:
 99                 get_news()
100                 print(\n)
101         tmp = current_time.second + 60 - start_time.second

最終的輸出 log:

Time_cnt: 1
Time_cnt: 2
Time_cnt: 3
Time_cnt: 4
Time_cnt: 5
Time_cnt: 6
Time_cnt: 7
Time_cnt: 8
Time_cnt: 9
Time_cnt: 10
Proxies: {http: http://106.110.198.18:25295}
今日 14:02 《漫威蜘蛛俠》否認畫面縮水:只是改變了太陽位置
今日 13:52 巴菲特:天天發Twitter對馬斯克沒好處
今日 13:48 網遊總量調控:大廠的一時之痛 VS 小廠的滅頂之災
今日 13:38 1.2m至2m均價,浩嵐旗艦店磨毛床品四件套59元
今日 13:37 索尼或於9月14日發布新款A7SIII全幅微單相機
今日 13:35 谷歌AI助理Google Assistant大升級:同時雙語識別
今日 13:12 小米工程師:年前見到了小米MIX 3工程機,產量充足
今日 12:56 小米無線充電器(通用快充版)發布:10W快充,69元
今日 12:53 《古墓麗影:暗影》要登WeGame?騰訊發布問卷調查
今日 12:37 疑似湖畔大學學員回應“心疼柳青”:我們不教語文和邏輯
今日 12:27 拼多多首份財報:營收27億元翻25倍,虧損翻65倍
08月29日 哆啦A夢正版授權,網易雲音樂蘋果iPhone 6/7/8/X系列手機殼19元
今日 12:26 B站“血小板吧反串黑”公告:永封相關賬號,訴諸法律
今日 12:22 手機淘寶迎重大更新:“猜你喜歡”躍至首頁二屏
今日 12:19 “初音未來”主題機械鍵鼠公布,蔥娘鍵盤約860元
今日 12:13 《生化危機2:重制版》PS4 Pro版演示:場景刻畫細節精美
今日 12:06 遭特朗普炮轟,谷歌回應稱指責“不屬實”
今日 12:03 英特爾為Windows 10設備推出新驅動,修復一系列重大問題
今日 11:51 雙星旗艦店網面運動鞋69→39元、啄木鳥彈力牛仔褲109→59元
今日 11:42 亞運會《英雄聯盟》中韓決賽回放:並未遭下架,暫無官方直播
今日 11:23 工信部:7月全國共查處“偽基站”違法犯罪案件21起
今日 11:19 《堡壘之夜》官方澄清:虛幻4神秘新平臺代號並非索尼PS5!
今日 11:12 R星Steam周末特惠:《俠盜獵車》全系列低至3折!
今日 11:03 滴滴之過
今日 11:00 蘋果秋季新品發布會信息匯總:中國特供雙卡iPhone XS,iOS 12拯救老機型
今日 10:55 蘋果iOS 12最新公測版遇Bug,解鎖或下拉菜單提醒升級
今日 10:50 營養暴下飯,仲景旗艦店招牌原味香菇醬10袋480g19.9元
今日 10:40 榮耀Magic2突現,華為要拿麒麟980搶蘋果高通風頭
今日 10:40 華為做電視,背後的物聯網戰略才是重點?
今日 10:31 微軟京東超級新品日:今日購Surface Go可享6期免最高補貼500元
今日 10:29 微信朋友圈八月十大謠言:使用@符號會被人工監控
今日 10:26 HB商店喜加一:特別好評遊戲《戰錘星際戰士》免費領
今日 10:16 “貴”族8848的沒落之路
今日 10:11 飛船裂縫導致國際空間站“漏氣”,NASA:不威脅人員安全
今日 10:08 蘋果要求重審專利侵權案遭美法官否決:賠償5億美元
今日 9:58 “我是開滴滴順風車的鬥魚主播”
今日 9:57 叫賣華住開房信息,暗網為何如此囂張?
今日 9:55 可雙肩/斜挎/手提,卡拉羊拉桿插件防盜三用包39元
今日 9:47 《戰地5》跳票後EA股價下跌8%,Origin高級會員可提前11天進入遊戲
今日 9:46 雷軍評價小米MIX 3:新一代全面屏,滑蓋形式的
今日 9:44 聯想Yoga Book C930雙屏筆電發布:電子墨水屏取代實體鍵盤
今日 9:38 1798元起,錘子堅果Pro2S手機10點再次開啟搶購
今日 9:35 武漢:網約車須加裝衛星定位和一鍵報警
今日 9:29 滑蓋新機曝光網友不敢相信直呼小米Note4,小米有品:MIX 3真機在此
08月26日 寬松休閑,凡客誠品旗艦店男士純棉日式牛津紡襯衫64元
今日 9:25 消息稱三星將向OPPO和小米提供可折疊手機屏幕
今日 9:15 這些價值上億美元的網站,背後居然都只有一個程序員
今日 9:08 榮耀、小米:滑蓋不解決一切問題
今日 9:07 10點開搶,小米8透明探索版今日再次發售
今日 9:04 聯想發布全球首款驍龍850筆記本Yoga C630:續航25小時


Time_cnt: 11
Time_cnt: 12
Time_cnt: 13
Time_cnt: 14
Time_cnt: 15
Time_cnt: 16
Time_cnt: 17
Time_cnt: 18
Time_cnt: 19
Time_cnt: 20
Proxies: {http: http://118.190.95.43:9001}
今日 14:02 《漫威蜘蛛俠》否認畫面縮水:只是改變了太陽位置
今日 13:52 巴菲特:天天發Twitter對馬斯克沒好處
今日 13:48 網遊總量調控:大廠的一時之痛 VS 小廠的滅頂之災
今日 13:38 1.2m至2m均價,浩嵐旗艦店磨毛床品四件套59元
今日 13:37 索尼或於9月14日發布新款A7SIII全幅微單相機
今日 13:35 谷歌AI助理Google Assistant大升級:同時雙語識別
今日 13:12 小米工程師:年前見到了小米MIX 3工程機,產量充足
今日 12:56 小米無線充電器(通用快充版)發布:10W快充,69元
今日 12:53 《古墓麗影:暗影》要登WeGame?騰訊發布問卷調查
今日 12:37 疑似湖畔大學學員回應“心疼柳青”:我們不教語文和邏輯
今日 12:27 拼多多首份財報:營收27億元翻25倍,虧損翻65倍
08月29日 哆啦A夢正版授權,網易雲音樂蘋果iPhone 6/7/8/X系列手機殼19元
今日 12:26 B站“血小板吧反串黑”公告:永封相關賬號,訴諸法律
今日 12:22 手機淘寶迎重大更新:“猜你喜歡”躍至首頁二屏
今日 12:19 “初音未來”主題機械鍵鼠公布,蔥娘鍵盤約860元
今日 12:13 《生化危機2:重制版》PS4 Pro版演示:場景刻畫細節精美
今日 12:06 遭特朗普炮轟,谷歌回應稱指責“不屬實”
今日 12:03 英特爾為Windows 10設備推出新驅動,修復一系列重大問題
今日 11:51 雙星旗艦店網面運動鞋69→39元、啄木鳥彈力牛仔褲109→59元
今日 11:42 亞運會《英雄聯盟》中韓決賽回放:並未遭下架,暫無官方直播
今日 11:23 工信部:7月全國共查處“偽基站”違法犯罪案件21起
今日 11:19 《堡壘之夜》官方澄清:虛幻4神秘新平臺代號並非索尼PS5!
今日 11:12 R星Steam周末特惠:《俠盜獵車》全系列低至3折!
今日 11:03 滴滴之過
今日 11:00 蘋果秋季新品發布會信息匯總:中國特供雙卡iPhone XS,iOS 12拯救老機型
今日 10:55 蘋果iOS 12最新公測版遇Bug,解鎖或下拉菜單提醒升級
今日 10:50 營養暴下飯,仲景旗艦店招牌原味香菇醬10袋480g19.9元
今日 10:40 榮耀Magic2突現,華為要拿麒麟980搶蘋果高通風頭
今日 10:40 華為做電視,背後的物聯網戰略才是重點?
今日 10:31 微軟京東超級新品日:今日購Surface Go可享6期免最高補貼500元
今日 10:29 微信朋友圈八月十大謠言:使用@符號會被人工監控
今日 10:26 HB商店喜加一:特別好評遊戲《戰錘星際戰士》免費領
今日 10:16 “貴”族8848的沒落之路
今日 10:11 飛船裂縫導致國際空間站“漏氣”,NASA:不威脅人員安全
今日 10:08 蘋果要求重審專利侵權案遭美法官否決:賠償5億美元
今日 9:58 “我是開滴滴順風車的鬥魚主播”
今日 9:57 叫賣華住開房信息,暗網為何如此囂張?
今日 9:55 可雙肩/斜挎/手提,卡拉羊拉桿插件防盜三用包39元
今日 9:47 《戰地5》跳票後EA股價下跌8%,Origin高級會員可提前11天進入遊戲
今日 9:46 雷軍評價小米MIX 3:新一代全面屏,滑蓋形式的
今日 9:44 聯想Yoga Book C930雙屏筆電發布:電子墨水屏取代實體鍵盤
今日 9:38 1798元起,錘子堅果Pro2S手機10點再次開啟搶購
今日 9:35 武漢:網約車須加裝衛星定位和一鍵報警
今日 9:29 滑蓋新機曝光網友不敢相信直呼小米Note4,小米有品:MIX 3真機在此
08月26日 寬松休閑,凡客誠品旗艦店男士純棉日式牛津紡襯衫64元
今日 9:25 消息稱三星將向OPPO和小米提供可折疊手機屏幕
今日 9:15 這些價值上億美元的網站,背後居然都只有一個程序員
今日 9:08 榮耀、小米:滑蓋不解決一切問題
今日 9:07 10點開搶,小米8透明探索版今日再次發售
今日 9:04 聯想發布全球首款驍龍850筆記本Yoga C630:續航25小時

你就可以每隔 10s 刷新下該網站上面的新聞流;

刷新周期在 line 87:

>>> if sec_cnt % 10 == 0:

# 請尊重他人勞動成果,轉載或者使用源碼請註明出處:http://www.cnblogs.com/AdaminXie

# 請不要利用爬蟲從事惡意攻擊或者違法活動

Python 利用 BeautifulSoup 爬取網站獲取新聞流