先說下需求:
最近打算搜集點源數據,豐富下生活。嗯,最近看到One這個APP蠻好的。每天想你推送一張圖和一段話。很喜歡,簡單不復雜。而我想要把所有的句子都保存下來,又不想要每個頁面都去手動查看。因此,就有了Python。之前有點Python基礎,不過沒有深入。現在也沒有深入,用哪學哪吧。
網站的內容是這樣的,我想要圖片和這段話:
(一)
一臺MAC電腦
(二)Python環境搭建(所有命令都是在terminal中輸入的)
- 安裝homebrew:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- 安裝pip:這里我在terminal中輸入
python -v
,homebrew會自動幫你升級Python到2.7.11版本的。2.7.11版本里自帶了pip工具。 - 安裝virtualenv:
pip install virtualenv
- 安裝request和beautifulsoup4:
pip install requests beautifulsoup4
參考這里
(三)分析
目的:找出三個內容所在的網頁標簽的位置,然后將它們提取出來。
網址:http://wufazhuce.com/one/1293
谷歌瀏覽器,右鍵->顯示網頁源代碼,然后就會彈出一堆HTML的東西了。這樣的:
我想要的內容是這段話:“即使熱戀者的情感是錯覺、幻象或自戀行為,那又何妨,所謂人生就是一段不斷追求情愛的路程。 by 森山大道”。它在圖中畫紅線的地方。在<heda>
標簽里的<meta>
中,之后會用到,先往下看。
圖片的鏈接在哪里?顯然不在<head>
中,往下找,然后就在<body>
中,發現2處和圖片類似的鏈接。看圖
哪個鏈接是呢,點擊去,發現后一個鏈接,也就是67行這個img標簽的鏈接是。
然后,我還想知道哪一天的圖和文字。嗯,在回到<head>
標簽里,很明顯有個<title>
,里面的東西就是我們要的。這樣:
<title>VOL.1271 - 「ONE · 一個」</title>
(四)python編碼
想要抓取網頁上的內容,又不想自己去解析HTML,只好求助萬能的Google了。然后就找到了上面的鏈接。主要有兩個工具:request加載網頁,BeautifulSoup4解析HTML。
首先,抓取我們需要的哪三個內容:
進入python環境,然后敲入下面的代碼:
import requests
import bs4
response = requests.get('http://wufazhuce.com/one/1295')
soup = bs4.BeautifulSoup(response.text,"html.parser")
這樣,就可以將網頁信息存儲到soup中了。你可以敲入print soup
試試。
接下來,我們獲得<title>VOL.1271 - 「ONE · 一個」</title>
中的數字1271
。怎么獲得呢,beautifulsoup4教程,提供了很好的方法,可以通過tag查找得到title的內容,然后截取字符串。termianl中輸入:
soup.title.string[3:7]
title是tag值,string是tag=title的字符串的值,也就是<title></title>
之間的值,因為只有一個<title>
tag,所以不用做判斷,直接獲取即可。
接下來,獲取一段話。
這段話在<meta>
中,而這里又有太多的<meta>
了,怎么辦。這里要用到select方法了,它可以查找所有的<meta>
,并返回一個列表。還要用到get方法,get可以獲得tag的屬性,如tag: <meta attr='abc'>
tag.get('attr')值等于abc。這里我們要獲取的屬性是name,通過name='description'來區分。
for meta in soup.select('meta'):
if meta.get('name') == 'description':
print meta.get('content')
接下來,在兩個img標簽中,查找第2個img標簽標定的鏈接。這里通過find_all方法,它可以查找所有的符合要求的標簽。
soup.find_all('img')[1]['src']
這樣,我們就把所需要的信息找出來了。
等等,之后我們還需要并發和保存文件。在此之前,先來看點別的。map函數有兩個參數,一個是函數,一個是序列。將序列的每個值,作為參數傳遞給函數,返回一個列表。參考這里
示例:
def echoInfo(num):
return num
data = map(echoInfo, range(0,10))
print data
結果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
然后并發, python可以跨平臺使用,自身提供了多進程支持模塊:multiprocessing。而pool可以用來創建大量的子進程。
保存數據到文件。這里我們是吧數據解析后存儲到字典中,然后序列化為JSON模型,最后保存到文件的。
即:字典->JSON模型->存儲到文件。
字典->JSON模型,使用的是JSON模塊的json.dumps方法,該方法有一個參數,參數為字典,返回值是JSON字符串。
JSON模型->文件,使用的是json.load方法,可以將JSON存儲到文件中。
全部的代碼示例如下:
import argparse
import re
from multiprocessing import Pool
import requests
import bs4
import time
import json
import io
root_url = 'http://wufazhuce.com'
def get_url(num):
return root_url + '/one/' + str(num)
def get_urls(num):
urls = map(get_url, range(100,100+num))
return urls
def get_data(url):
dataList = {}
response = requests.get(url)
if response.status_code != 200:
return {'noValue': 'noValue'}
soup = bs4.BeautifulSoup(response.text,"html.parser")
dataList["index"] = soup.title.string[4:7]
for meta in soup.select('meta'):
if meta.get('name') == 'description':
dataList["content"] = meta.get('content')
dataList["imgUrl"] = soup.find_all('img')[1]['src']
return dataList
if __name__=='__main__':
pool = Pool(4)
dataList = []
urls = get_urls(10)
start = time.time()
dataList = pool.map(get_data, urls)
end = time.time()
print 'use: %.2f s' % (end - start)
jsonData = json.dumps({'data':dataList})
with open('data.txt', 'w') as outfile:
json.dump(jsonData, outfile)