日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
用Python將微信熱文轉(zhuǎn)換成Word文檔|神級(jí)操作

 不得不說微信公眾號(hào)已經(jīng)成為了一個(gè)開放平臺(tái),每天數(shù)以萬計(jì)的微信公眾號(hào)文章在這產(chǎn)生,我們關(guān)注一個(gè)微信公眾號(hào)每天便可以看到新的文章,我們同時(shí)也不知不覺的將好的文章分享到給朋友。

那么如何保存一個(gè)好的文章呢?普遍選擇收藏,然而在這里,我提供一個(gè)更巧妙的方法,直接轉(zhuǎn)換成word文檔保存在電腦里面。即便是以后文章404了,我們還可以看得到嘛。

1、微信熱文源代碼分析

一篇微信文章,url開頭一定是https://mp.weixin.qq.com/s/,后面跟著一長(zhǎng)串字符串,比如qLjifoyinoVN5i5vjW0f7w。

查看網(wǎng)頁源代碼,我們發(fā)現(xiàn)

微信熱文的網(wǎng)頁源代碼很長(zhǎng),即便是上面的一個(gè)很簡(jiǎn)短的文章,但我們要從中提取到我們想要的東西,比如

 
 
 
 
  1. 普京再次出面

妥妥的文章題目,我們要把它保存為word文檔,題目肯定少不了。

 
 
 
 
  1.  
  2.  
     
  3.    環(huán)球時(shí)報(bào) 
  4.     
  5.    

     

  6.       
  7.      hqsbwx

     
  8.    

     

  9.       
  10.      報(bào)道多元世界 解讀復(fù)雜中國(guó)

     
  11.  

這里一下子就提示了這篇文章是那個(gè)微信號(hào)發(fā)布的,而且還有微信號(hào)的介紹,這也是我們需要的信息

 
 
 
 

這個(gè)就是正文的標(biāo)簽了,這個(gè)標(biāo)簽里面蘊(yùn)含著正文,下面是正文的第一個(gè)標(biāo)簽,我們將它格式化一下,如下

我們發(fā)現(xiàn)section套了很多層,但是實(shí)際上,這第一個(gè)標(biāo)簽就這一句話是重點(diǎn):“俄總統(tǒng)普京同納卡沖突雙方領(lǐng)導(dǎo)人舉行電話會(huì)談?!?/p>

下一個(gè)標(biāo)簽也是section,但是涵蓋了好幾句話。我們發(fā)現(xiàn)了span標(biāo)簽和strong標(biāo)簽。而且出現(xiàn)了很多次rgb(),我們知道rgb是代表標(biāo)簽內(nèi)字體的顏色的。當(dāng)然,strong是標(biāo)簽內(nèi)加粗咯。

 
 
 
 

另一個(gè)圖片標(biāo)簽

 
 
 
 

這個(gè)是圖片的標(biāo)簽,里面蘊(yùn)含著很多重要的東西,比如,data-type="gif",表明這是一個(gè)gif文件,src指向了圖片的地址,data-w="200",代表圖片的寬度,這很重要。

格式化后的內(nèi)容如下所示

標(biāo)簽套標(biāo)簽,讓人眼花繚亂。

不過,還是一步一步來吧。

2、設(shè)計(jì)代碼,步步分析

這一步我們需要開始編寫代碼了,python-docx是一個(gè)生成和處理docx的第三方庫,使用pip install python-docx 一鍵下載

需要用到的第三方庫有,python-docx,bs4(用于html解析處理)

 
 
 
 
  1. from docx import Document 
  2. from docx.oxml.ns import qn 
  3. import re 
  4. from docx.shared import RGBColor,Inches,Pt 
  5. from urllib.request import urlopen,Request 
  6. from bs4 import BeautifulSoup 
  7. from docx.enum.text import WD_PARAGRAPH_ALIGNMENT 
  8. import io 
  9. from os.path import join 
  10. qingqiu={'User-Agent':"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", 
  11.       'Accept':'text/plain, text/html' 
  12.       }

編寫一個(gè)簡(jiǎn)單的過濾函數(shù),因?yàn)槲覀兊玫轿恼聵?biāo)題后,需要將文章標(biāo)題中一些字符刪去,比如換行符,空格,以及{}?

/|\等字符,因?yàn)楹羞@些字符的字符串不能做文件名

 
 
 
 
  1. def guolv(text): 
  2.     t = re.sub('\s', '', text) 
  3.     t = re.sub('[?<>()[\]{}|]', ':', t) 
  4.     return t

假設(shè)微信url已經(jīng)確定,在這里我們編寫一個(gè)類,這個(gè)類專門用來處理的。

 
 
 
 
  1. class WX_doc(): 
  2.     def __init__(self, url, path): 
  3.         self.img_num = 0 
  4.         self.doc = Document() 
  5.         self.doc.styles['Normal'].font.name = '微軟雅黑' 
  6.         self.doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '微軟雅黑') 
  7.         self.url = url 
  8.         self.path = path

self.img_num是針對(duì)img處理的,每處理一個(gè)img,self.img_num+=1,請(qǐng)注意,最好設(shè)置好文章的字體,因?yàn)閜ython-docx默認(rèn)字體顯示中文會(huì)比較難看……不信你可以去試試。當(dāng)然也可以將字體設(shè)為宋體

url是指微信熱文的鏈接,path是Word文檔處理完后的保存路徑。

接下來是一個(gè)插入一個(gè)標(biāo)題的方法。

注:

我們?cè)O(shè)單獨(dú)的def開頭的為函數(shù),包含在class內(nèi)的def開頭的為方法

 
 
 
 
  1. def head(self, title, lv=3, size=13): 
  2.     p = self.doc.add_heading('', lv) 
  3.     p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER 
  4.     r = p.add_run(title) 
  5.     r.font.name = '微軟雅黑' 
  6.     r.font.color.rgb = RGBColor(0, 0, 0) 
  7.     r.font.size = Pt(size) 
  8.     r._element.rPr.rFonts.set(qn('w:eastAsia'), u'微軟雅黑')

將標(biāo)題插入后,設(shè)置為居中,顏色黑色,大小默認(rèn)13,字體微軟雅黑。

2、巧妙處理標(biāo)簽

對(duì)于正文來講,標(biāo)簽套標(biāo)簽讓人眼花繚亂,然而我們?nèi)绾翁幚碚闹械奈淖郑瑘D像甚至表格呢?

,對(duì)于標(biāo)簽套標(biāo)簽,我設(shè)計(jì)的思路是:

用對(duì)應(yīng)的標(biāo)簽方法處理標(biāo)簽

 
 
 
 
  1. hd = Request(self.url, headers=qingqiu) 
  2. a = urlopen(hd) 
  3. b = a.read() 
  4. bbb = b.decode('UTF-8') 
  5. bs = BeautifulSoup(bb, 'lxml') 
  6. h2 = bs.find('h2', {'class': "rich_media_title"}) 
  7. title = guolv(h2.text) 
  8. self.head(title, 2, 18) 
  9. pingtai = bs.find('strong', {'class': "profile_nickname"}) 
  10. PMV=bs.findAll('span',{'class':'profile_meta_value'}) 
  11. p = self.doc.add_paragraph() 
  12. r = p.add_run('%s' % pingtai.text) 
  13. r.font.bold = True 
  14. r.font.color.rgb = RGBColor(0, 191, 255) 
  15. r.font.size = Pt(12) 
  16. r=p.add_run('(%s: %s)'%(PMV[0].text,PMV[1].text)) 
  17. r.font.size = Pt(9) 
  18. wb = bs.find('div', {'class': "rich_media_content"})

這樣一處理,bs就是整篇微信文章的BeautifulSoup結(jié)構(gòu)的html,這樣處理就方便的多。

對(duì)于標(biāo)題和發(fā)布者的,我們放到后面處理,現(xiàn)在要考慮正文的處理,wb就是正文的bs結(jié)構(gòu)。

如何編寫標(biāo)簽函數(shù)?我假定只關(guān)注字體的顏色和加粗,其余字體大小不考慮(這樣的話保存的文章樣式是一致的),使用RGB代表顏色,比如RGB=(0,0,0)就是純黑了,bold代表加粗,bold=True就是加粗。

標(biāo)簽

p代表段落,p標(biāo)簽內(nèi)的文字會(huì)形成一個(gè)段。對(duì)應(yīng)doc中的add_paragraph方法,接下來我們編寫WX_doc的第一個(gè)標(biāo)簽處理方法。默認(rèn)字體顏色黑色,不加粗。

 
 
 
 
  1. def para(self, label): 
  2.     p = self.doc.add_paragraph('') 
  3.     for i in label: 
  4.         self.transit(i,p, (0, 0, 0), False)

這樣就完了,主要操作就是,將p中每一個(gè)標(biāo)簽?zāi)贸鰜恚唤otransit函數(shù)處理,transit會(huì)針對(duì)相應(yīng)的標(biāo)簽交給相應(yīng)的標(biāo)簽方法。

但是如果出現(xiàn)這樣的情況,p內(nèi)含p,就像section一樣一層套一層,那么需要另一個(gè)p處理方法

 
 
 
 
  1. def para2(self,label,p,RGB,bold): 
  2.     "解決p內(nèi)含p的情況" 
  3.     for i in label: 
  4.         self.transit(i,p, RGB, bold)

對(duì)于后面的標(biāo)簽處理方法,我們規(guī)定,需4個(gè)參數(shù),第一個(gè)BeautifulSoup結(jié)構(gòu)的標(biāo)簽label,第二個(gè),所屬的段落p,為doc.add_paragraph方法返回的段落p,第三個(gè)和第四個(gè)為RGB和bold。

標(biāo)簽

Span標(biāo)簽出險(xiǎn)率極高,基本上每段文字都會(huì)出現(xiàn),我們假定span中的style設(shè)定文字的顏色。

比如這一段span

 
 
 
 
  1. 普京與兩國(guó)領(lǐng)導(dǎo)人討論了本月9日三方簽訂的停火協(xié)議落實(shí)問題。各方對(duì)當(dāng)前沖突接觸線的平靜局勢(shì)感到滿意。

多次觀察后,編寫的處理方法如下

 
 
 
 
  1. def span(self, label, p, RGB, bold): 
  2.     attr = label.attrs.get('style') 
  3.     if attr: 
  4.         ys = re.findall('(?<=rgb\()[\s\S]+?(?=\))', attr) 
  5.     else: 
  6.         ys=[] 
  7.     if ys: 
  8.         rgb = re.findall('\d+', ys[0]) 
  9.         r = int(rgb[0]) 
  10.         g = int(rgb[1]) 
  11.         b = int(rgb[2])
  12.         RGB = (r, g, b)
  13.     for i in label: 
  14.         if i.name == None: 
  15.             self.text(i,p, RGB, bold) 
  16.         elif i.name == "strong": 
  17.             self.strong(i,p, RGB, bold) 
  18.         else: 
  19.             self.transit(i,p, RGB, bold)

當(dāng)BeautifulSoup結(jié)構(gòu)下的標(biāo)簽結(jié)構(gòu)為None時(shí),它就是一段純文字

Text 純文字處理

處理純文字用的方法,需要注意的是,要將文字中的換行符刪去。

 
 
 
 
  1. def text(self, i, p, RGB, bold): 
  2.     i=str(i) 
  3.     ii=i.replace('\n','') 
  4.     r = p.add_run(i) 
  5.     r.font.bold = bold 
  6.     r.font.color.rgb = RGBColor(RGB[0], RGB[1], RGB[2])

標(biāo)簽

Strong就是加粗

 
 
 
 
  1. def strong(self, label, p, RGB, bold): 
  2.     for i in label: 
  3.         if i.name == None: 
  4.             self.text(i,p, RGB, True) 
  5.         elif i.name == 'span': 
  6.             self.span(i,p, RGB, True)

標(biāo)簽

Section常常會(huì)出現(xiàn)套疊的情況,即便是里面有字體顏色大小的指示,我還是以span指示的顏色為準(zhǔn)。那么如何正確處理section便是一個(gè)難題。

 
 
 
 
  1.         
  2.          俄總統(tǒng)網(wǎng)站聲明截圖

 上面的section中出現(xiàn)了span,所以思路來了,遍歷section中的標(biāo)簽,如果出現(xiàn)span和stong,直接按段落處理

 
 
 
 
  1. def section(self,label): 
  2.     for i in label: 
  3.         if i.name=='p': 
  4.             self.para(i) 
  5.         elif i.name in ['span','strong']: 
  6.             self.para(label) 
  7.             return 0 
  8.         elif i.name=='section': 
  9.             self.section(i) 
  10.         elif i.name in ['ul','ol']: 
  11.             self.ul2(i) 
  12.         elif i.name=='img': 
  13.             self.img(i) 
  14.         elif i.name in ['br','svg','center']: 
  15.             pass 
  16.         elif i.name=='blockquote': 
  17.             self.blockquote(i) 
  18.         elif i.name=='pre': 
  19.             self.pre(label) 
  20.         else: 
  21.             print('section中:%s:%s'%(i.name,str(i)))

最后else表示沒有這個(gè)標(biāo)簽的處理函數(shù),就提示這個(gè)標(biāo)簽的位置,以及名稱,所含內(nèi)容

標(biāo)簽

我們知道img標(biāo)簽是圖像,一篇文章加上圖像可謂畫龍點(diǎn)睛,現(xiàn)在很少出現(xiàn)沒有圖的文章了,正所謂有圖有真相。

以下面兩個(gè)圖像為例

 
 
 
 

我們發(fā)現(xiàn)data-w是設(shè)定圖片的寬度,當(dāng)圖片過大的時(shí)候,需要將圖片寬度設(shè)定好。Img處理函數(shù)如下

 
 
 
 
  1. def img(self, label): 
  2.     src = label.attrs['src'] 
  3.     da_s = label.attrs.get('data-s') 
  4.     data_type = label.attrs.get('data-type') 
  5.     data_w = label.attrs.get('data-w') 
  6.     self.img_num += 1 
  7.     a = urlopen(src) 
  8.     b = a.read() 
  9.     path = io.BytesIO(b) 
  10.     if da_s: 
  11.         num = re.findall('\d+', da_s) 
  12.         h = int(num[0]) // 75 
  13.         w = int(num[1]) // 75 
  14.         if w > 6: 
  15.             self.doc.add_picture(path, width=Inches(6)) 
  16.         else: 
  17.             self.doc.add_picture(path, width=Inches(w), height=Inches(h)) 
  18.     elif data_w: 
  19.         data_w = int(data_w) 
  20.         if data_w < 75: 
  21.             # 標(biāo)簽太小,直接忽略 
  22.             print('忽略太小圖片%d.%s' % (self.img_num, data_type)) 
  23.         elif data_w > 450: 
  24.             self.doc.add_picture(path, width=Inches(6)) 
  25.         else: 
  26.             self.doc.add_picture(path, width=Inches(data_w / 75)) 
  27.     else: 
  28.         self.doc.add_picture(path, width=Inches(6)) 
  29.     print("圖片%d打入成功!" % (self.img_num - 1))

transit方法

最后我們編寫transit方法

 
 
 
 
  1. def transit(self, label, p, RGB, bold): 
  2.     "本函數(shù)提供label的中轉(zhuǎn)方案 其中br由中轉(zhuǎn)方案解決" 
  3.     if label.name == 'span': 
  4.         self.span(label, p,RGB,bold) 
  5.     elif label.name == None: 
  6.         self.text(label, p,RGB,bold) 
  7.     elif label.name in ['strong','em']: 
  8.         self.strong(label, p,RGB,bold) 
  9.     elif label.name=='section': 
  10.         self.section(label) 
  11.     elif label.name =='p': 
  12.         self.para2(label,p,RGB,bold) 
  13.     elif label.name == 'img': 
  14.         self.img(label) 
  15.     elif label.name in ['br','svg','mpcpc','center']: 
  16.         pass 
  17.     elif label.name == 'a': 
  18.         self.link(label, p,RGB,bold) 
  19.     elif label.name == 'iframe': 
  20.         self.iframe(label, p) 
  21.     elif label.name == 'blockquote': 
  22.         self.blockquote(label) 
  23.     elif label.name == 'ul': 
  24.         self.ul(label, p) 
  25.     elif label.name=='pre': 
  26.         self.pre(label) 
  27.     else: 
  28.         print('p中:%s %s'%(str(label.name),str(label.text))) 
  29.         t = label.text 
  30.         if len(t) < 2: 
  31.             return 0 
  32.         r = p.add_run(t) 
  33.         r.font.bold = bold 
  34.         r.font.color.rgb = RGBColor(RGB[0], RGB[1], RGB[2])

transit函數(shù)要處理一個(gè)標(biāo)簽,如果已經(jīng)編寫好了這個(gè)標(biāo)簽方法,那么將這個(gè)標(biāo)簽交給對(duì)應(yīng)的標(biāo)簽方法處理,如果沒有,就提示這個(gè)標(biāo)簽的位置,以及名稱,所含內(nèi)容

main 核心處理

最后我們當(dāng)然是處理并且轉(zhuǎn)換成文檔啦,加入文章標(biāo)題,發(fā)布者,和內(nèi)容,直接發(fā)完整代碼吧,如下:

 
 
 
 
  1. def main(self) -> None: 
  2.     hd = Request(self.url, headers=qingqiu) 
  3.     a = urlopen(hd) 
  4.     b = a.read() 
  5.     bbb = b.decode('UTF-8') 
  6.     bs = BeautifulSoup(bb, 'lxml') 
  7.     h2 = bs.find('h2', {'class': "rich_media_title"}) 
  8.     title = guolv(h2.text) 
  9.     self.head(title, 2, 18) 
  10.     pingtai = bs.find('strong', {'class': "profile_nickname"}) 
  11.     PMV=bs.findAll('span',{'class':'profile_meta_value'}) 
  12.     p = self.doc.add_paragraph() 
  13.     r = p.add_run('%s' % pingtai.text) 
  14.     r.font.bold = True
  15.     r.font.color.rgb = RGBColor(0, 191, 255) 
  16.     r.font.size = Pt(12) 
  17.     r=p.add_run('(%s: %s)'%(PMV[0].text,PMV[1].text)) 
  18.     r.font.size = Pt(9) 
  19.     wb = bs.find('div', {'class': "rich_media_content"}) 
  20.     for i in wb: 
  21.         if i.name =='p': 
  22.             self.para(i) 
  23.         elif i.name=='section': 
  24.             self.section(i) 
  25.         elif i.name == 'blockquote': 
  26.             self.blockquote(i) 
  27.         elif i.name == 'table': 
  28.             self.table(i) 
  29.         elif i.name in[None,'center','hr']: 
  30.             pass 
  31.         elif i.name in ['h1', 'h2', 'h3','h4']: 
  32.             self.head(i.text, int(i.name[1]) + 1) 
  33.         elif i.name in ['ul','ol']: 
  34.             self.ul2(i)
  35.          elif i.name == 'pre': 
  36.             self.pre(i) 
  37.         else: 
  38.             print("%s"%str(i)) 
  39.     self.save_docx(title) 
  40.     wz_pa=join(self.path,title+'.docx') 
  41.     print('文檔保存成功!保存路徑:%s'%wz_pa) 
  42.     self.ok=False 
  43.     print(wz_pa)

3、實(shí)戰(zhàn)測(cè)試

運(yùn)行后輸入微信url,結(jié)果如下:

保存下來的Word文檔如下:

4、其他標(biāo)簽的處理說明

剛剛我們僅僅是編寫了section,span,p,strong等標(biāo)簽,就可以對(duì)付一個(gè)簡(jiǎn)單的文章,但是實(shí)際上還有其他的標(biāo)簽,僅僅是這篇文章沒出現(xiàn)而已。所以為了讓這程序越來越好,我們需要添加一些標(biāo)簽處理的方法。

標(biāo)簽

Blockquote代表著引用,比如文章引用的哪句話,抄了哪些文獻(xiàn)的句子,都用這個(gè)標(biāo)簽。為了和正文區(qū)別,我將字體大小設(shè)置為9默認(rèn)顏色(100,100,100)

 
 
 
 
  1. def blockquote(self, label): 
  2.     "定義一個(gè)摘自另一個(gè)源的塊引用" 
  3.     p = self.doc.add_paragraph('') 
  4.     p.style.font.size = Pt(9) 
  5.     for i in label: 
  6.         self.transit(i,p,(100,100,100),False)