Python爬取新浪英超曼联文章内页--bs4,json,txt和csv以及编码
之后使用json解析。
必須仔細觀察json的結構,而且還需要不斷地斷點調試。
import?requests
import?json
headersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
#network headers里面
url_sport =?"http://interface.sina.cn/pc_zt_roll_news_index.d.html?&subjectID=64558&channel=sports"
# json_url = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports&callback=jsonpcallback1483559621857'
json_url =?'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports'
jsContent = requests.get(json_url,?headers?= headersIm).content
print?jsContent
jsDict = json.loads(jsContent)
jsResult = jsDict['result']
jsData = jsResult['data']
for?each?in?jsData:
????????print?each['title']
今天的結果:
穆帥示愛曼聯球迷+球隊 他終成“快樂的一個”? 7戰6球!伊布當選英超月最佳 力壓切爾西王牌 曼聯大將自曬縫針照片 穆帥手下他已成紅魔樞紐 打臉!誰說穆里尼奧會毀了曼聯兩大妖王? 曝穆帥欲簽一昔日愛將 在皇馬切爾西都用過他 ......
? ?雖然爬取網頁信息,爬的不多,但是通常有兩大方法:一個是從網頁本身入手用lxml定位相應的h5元素,另一個是直接找信息源,通常是json。
又運行了一下程序,得到的結果是:
曼聯獵物正式提交轉會申請 同胞豐特或馳援鳥叔 曼聯宣布12月最佳球員 伊布力壓兩核心首當選......
證明這個爬蟲確實是爬取動態網站的。
沒做完的部分:將標題,內容都整理好,只爬取前20條信息就足夠了(或者加上后面10頁的內容),進入內頁后,將文章的文字部分也提取出來。
一、問題:
顯然,只爬取標題是不夠的,最主要的還是url鏈接,內頁的正文:
foreach injsData:
??? print each['title']+" "+each['url']
顯然,所有有用的信息都已經在jsData這個列表里面,而現在為止,有兩個問題:
1.??????下一頁的數據如何爬取;
2.??????新聞內頁的文字如何爬取。
二、分析
首先,下一頁的數據。點擊底下的頁碼的時候,數據變化,而瀏覽器地址欄是不變的,所以還是要從json源的地址入手。而通過觀察json源地址:http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page=1&channel=sports可知,page=1,這個1很可能是相應頁碼,同時,共114頁,我們只取前20。
for i in range(1, 21):print i所以可以構造一個函數專門來讀取標題+日期+正文。
?
以頁面:http://sports.sina.com.cn/g/pl/2017-01-07/doc-ifxzkfuk2454395.shtml為例,可知想得到的信息分別是:
標題:<h1id="artibodyTitle">歐文:穆帥別抱怨裁判專注比賽吧瓜帥沒必要改變</h1>
?????????? title_news =bsObj.find("h1",{"id":"artibodyTitle"}).string???? #獲取h1標簽的內容
日期:<spanid="pub_date">2017年01月07日07:01</span>
?????????? date_news =bsObj.find("span", {"id":"pub_date"}).string? ?????#同上
內容:<divclass="BSHARE_POP blkContainerSblkCon clearfixblkContainerSblkCon_14" id="artibody">下的所有p標簽的內容。
?????????? content_news =bsObj.find("",{"id":"artibody"}).findAll("p")?? #先找到id為artibody的元素,再向下尋找p標簽
??? for content in content_news:
??????? print content.get_text()??????????????????? #獲得每一個p標簽的內容
三、構造
至此,這個函數已寫完,解析新聞內頁的函數:
def getNewsContent(url_news):html_WebPage = requests.get(url_news,headers = headersIm)html_WebPage.encoding = 'utf-8'html_WebText = html_WebPage.textbsObj = BeautifulSoup(html_WebText, 'lxml')???? #shtml的解析使用lxml方式title_news = bsObj.find("h1",{"id":"artibodyTitle"}).string? #獲取h1標簽的內容date_news = bsObj.find("span", {"id": "pub_date"}).string?????? #同上content_news = bsObj.find("", {"id":"artibody"}).findAll("p")?? #先找到id為artibody的元素,再向下尋找p標簽for content in content_news:print content.get_text()????? #獲得每一個p標簽的內容?
像這種:http://k.sina.cn/article_5695956221_1538164fd02000165x.html?cre=aspect&mod=2L&loc=27&r=0&doct=0&rfunc=39&tj=none&s=0&from=sports&vt=4就不解析了,所以還要用到python的try...except。另外就是把標題,時間,內容,都存儲為csv和txt,后面我分別寫。
???????? 然而,獲得的標題,時間,內容,經過測試,都是NavigableString類型的,需要把這種類型寫入txt。只要在這種對象后面加上.encode('utf-8')即可轉換:title_news = bsObj.find("h1",{"id":"artibodyTitle"}).string.encode('utf-8')
四、寫入txt
???????? 最終的程序,把文章標題,日期,和內容存儲在txt文檔中(爬小說像不像):
# encoding=utf-8 注釋可用中文 import requests import json from bs4 import BeautifulSoupheadersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} f = open("news.txt", 'a') def getNewsContent(url_news):html_WebPage = requests.get(url_news,headers = headersIm)html_WebPage.encoding = 'utf-8'html_WebText = html_WebPage.textbsObj = BeautifulSoup(html_WebText, 'lxml')???? #shtml的解析使用lxml方式try:title_news = bsObj.find("h1",{"id": "artibodyTitle"}).string.encode('utf-8')???? #獲取h1標簽的內容,.encode('utf-8')轉換為strdate_news = bsObj.find("span", {"id": "pub_date"}).string.encode('utf-8')?????? #同上content_news = bsObj.find("", {"id":"artibody"}).findAll("p")?? #先找到id為artibody的元素,再向下尋找p標簽f.write(title_news.rstrip()+'----'+date_news.lstrip())? #將標題和日期用----連接,并刪除標題右側和日期左側的空格回車等,規范格式 寫入for content in content_news:news_text = content.get_text().encode('utf-8')??????????????????? #獲得每一個p標簽的內容,轉換為strf.write(news_text)??????????????????? #寫入txtf.write('\n')??????????? #文章末尾加換行符,區別兩塊新聞except:passfinally:passdef newsListPages(urlPages):jsContent = requests.get(urlPages, headers=headersIm).content?? #requsets解析文章列表jsDict = json.loads(jsContent)??????? #將內容用json庫解析jsResult = jsDict['result'] jsData = jsResult['data']for each in jsData:newsUrl = each['url']?? #獲得相應文章的urlgetNewsContent(newsUrl) #函數解析文章內頁內容for i in range(1, 3):url_json = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page='+str(i)+'&channel=sports'#構造json數據源的地址newsListPages(url_json)f.close()原理:分析從上至下,構建從下至上。首先分析樹狀結構,之后再構建解析文章—解析文章列表。但是,這樣單線程似乎有點慢,如果用多線程的方式,首先需要構建文章列表,再用函數進行統一解析。
結果:
尷尬!魯尼找對手換球衣被拒 來自曼城的恨(圖)----2017年01月08日01:11
??????????????????????? 新浪體育訊 曼聯4-0大勝雷丁一戰,對于魯尼本人意義非凡,此役他追平了隊史射手王查爾頓爵士249球的紀錄。按理說,這樣一場比賽,誰都想沾沾魯尼的喜氣,但是雷丁后衛喬治-埃文斯便是個另類,他拒絕了魯尼主動交換球衣的請求,原因是什么呢?
五、寫入csv
???????? 寫入csv格式類似:
# encoding=utf-8 注釋可用中文 import requests import json from bs4 import BeautifulSoup import csv import codecs? #保證csv能正確寫入的庫headersIm = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} csvfile = file('csv_test.csv', 'wb')??? #創建csv文件,并準備寫入 csvfile.write(codecs.BOM_UTF8)? #csv寫入中文必備 writer = csv.writer(csvfile)??? #構建寫入對象 writer.writerow(['標題', '日期', '內容']) def getNewsContent(url_news):html_WebPage = requests.get(url_news,headers = headersIm)html_WebPage.encoding = 'utf-8'html_WebText = html_WebPage.textbsObj = BeautifulSoup(html_WebText, 'lxml')???? #shtml的解析使用lxml方式try:title_news = bsObj.find("h1",{"id": "artibodyTitle"}).string.encode('utf-8')???? #獲取h1標簽的內容,.encode('utf-8')轉換為strdate_news = bsObj.find("span", {"id": "pub_date"}).string.encode('utf-8')?????? #同上content_news = bsObj.find("", {"id":"artibody"}).findAll("p")?? #先找到id為artibody的元素,再向下尋找p標簽content_str = ''for content in content_news:news_text = content.get_text().encode('utf-8')??????????????????? #獲得每一個p標簽的內容,轉換為strcontent_str += news_text????? #將文章正文存儲在相應字符串中writer.writerow([title_news, date_news, content_str])?? #構建每一行的格式,并寫入except:passfinally:passdef newsListPages(urlPages):jsContent = requests.get(urlPages, headers=headersIm).content?? #requsets解析文章列表jsDict = json.loads(jsContent)??????? #將內容用json庫解析jsResult = jsDict['result']jsData = jsResult['data']for each in jsData:newsUrl = each['url']?? #獲得相應文章的urlgetNewsContent(newsUrl) #函數解析文章內頁內容for i in range(1, 3):url_json = 'http://interface.sina.cn/pc_zt_api/pc_zt_press_news_doc.d.json?subjectID=64558&cat=&size=40&page='+str(i)+'&channel=sports'#構造json數據源的地址newsListPages(url_json)csvfile.close()?
六、總結:
???????? request負責獲取html頁面,json負責解析數據源,bs負責解析html內頁獲取相關內容(中間涉及編碼問題,在stackoverflow找到答案),最后是寫入txt(自帶函數),寫入csv(csv和codecs模塊)。
總結
以上是生活随笔為你收集整理的Python爬取新浪英超曼联文章内页--bs4,json,txt和csv以及编码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Delphi 获取菜单高度、标题栏高度、
- 下一篇: Excel批量删除空行的几种方法