Python+PhantomJS+selenium+BeautifulSoup實(shí)現(xiàn)簡(jiǎn)易網(wǎng)絡(luò)爬蟲(chóng)
簡(jiǎn)易網(wǎng)絡(luò)小爬蟲(chóng)飒硅,目標(biāo)站:http://www.toutiao.com/
已實(shí)現(xiàn)的功能
日期 | 功能 |
---|---|
2017.08.12 | 可獲取首頁(yè)輪播圖數(shù)據(jù)并保存到本地?cái)?shù)據(jù)庫(kù) |
2017.08.16 | 可獲取首頁(yè)新聞列表每一項(xiàng)的全部數(shù)據(jù)(作者頭像除外)并保存到本地?cái)?shù)據(jù)庫(kù) |
僅供學(xué)習(xí)使用倦踢,如有侵權(quán),敬請(qǐng)?jiān)彙?lt;(?????)>
Github地址: https://github.com/LalaTeam/PythonTrip
介紹
PhantomJS+selenium可以說(shuō)是...無(wú)敵的...
一一介紹一下:
PhantomJS: 實(shí)質(zhì)上就是一個(gè)沒(méi)有界面的瀏覽器,最主要的功能是能夠讀取js加載的頁(yè)面耗帕。
selenium: 瀏覽器自動(dòng)化測(cè)試框架.能夠模擬用戶的一些行為操作,比如填寫(xiě)指定輸入框,下拉操作等。
BeautifulSoup: 它是python的一個(gè)庫(kù)彪标,最主要的功能是從網(wǎng)頁(yè)抓取數(shù)據(jù)。配合lxml解析,快速獲取指定標(biāo)簽掷豺。
設(shè)計(jì)
基本思路:
- 利用PhantomJS模擬請(qǐng)求url
- 拿到網(wǎng)頁(yè)源碼,解析xml
- 獲取指定標(biāo)簽
- 根據(jù)標(biāo)簽?zāi)玫叫枰膶傩灾?/li>
- 存入本地?cái)?shù)據(jù)庫(kù)
網(wǎng)站分析
首先看一下我們能要拿的數(shù)據(jù)
首頁(yè)有一個(gè)輪播圖和一個(gè)新聞列表
輪播圖包括圖片和文字標(biāo)題
新聞列表包括圖片,標(biāo)題,時(shí)間,分類(lèi),作者昵稱,評(píng)論數(shù)等等
打開(kāi)瀏覽器開(kāi)發(fā)者模式,分析一下標(biāo)簽內(nèi)容,
發(fā)現(xiàn)每個(gè)標(biāo)簽都帶有一個(gè)類(lèi)似key的東西作為唯一標(biāo)識(shí),
截取a標(biāo)簽的href屬性group后面的一串?dāng)?shù)字作為唯一標(biāo)識(shí),
點(diǎn)擊每一條新聞,發(fā)現(xiàn)新聞詳情的Url是頭條首頁(yè)Url+這個(gè)唯一標(biāo)識(shí),
新聞詳情url暫時(shí)不獲取,這里只是先獲取首頁(yè)數(shù)據(jù).
再分析一下,
每一類(lèi)標(biāo)簽都是相同的標(biāo)簽名并且有相同的class,這樣就好辦了許多,只需要找到這一堆相同class的標(biāo)簽,再遍歷獲取里面的屬性值就可以了.
想到這里,基本就可以開(kāi)工了,
但實(shí)際上還是有一個(gè)問(wèn)題,
就是新聞列表不是一次性加載出來(lái)的,并且新聞的圖片是懶加載的,怎么辦?
思前想后,還是利用PhantomJS去滾動(dòng)頁(yè)面,
由于圖片是懶加載捞烟,所以必須滾動(dòng)一遍到底部停留3秒才可以拿到圖片URL 否則是圖片拿到的是svg+xml的Base64,
一直獲取到新聞時(shí)間為一天前就停止獲取,
但是這樣還是會(huì)獲取到有重復(fù)的新聞,
所以,還是利用它自帶的key去判斷是否已存在,不存在則存入數(shù)據(jù)庫(kù).
Perfect~
開(kāi)工
driver = webdriver.PhantomJS()
driver.get(web_url)
# driver.page_source:網(wǎng)頁(yè)源碼
# 利用lxml解析源碼拿到標(biāo)簽
# 找到指定的一類(lèi)標(biāo)簽
item_tags = BeautifulSoup(driver.page_source, 'lxml')
.find_all('div', class_='bui-box single-mode')
獲取每一類(lèi)數(shù)據(jù)的標(biāo)簽
for itemTag in item_tags:
# key
k = itemTag.find('div', class_='bui-left single-mode-lbox')
.a['href'].split('/')[2]
# 圖片
u = itemTag.find('div', class_='bui-left single-mode-lbox').a.img['src']
# 時(shí)間
t = itemTag.find('div', class_='single-mode-rbox')
.find('span', class_='footer-bar-action').text
# 標(biāo)題
title = itemTag.find('div', class_='title-box').a.text
# 分類(lèi)
type = itemTag.find('div', class_='bui-left footer-bar-left').a.text
# 作者頭像
# head = itemTag.find('div', class_='single-mode-rbox')
# .find('a', class_='footer-bar-action media-avatar')
# 作者昵稱
name = itemTag.find('div', class_='bui-left footer-bar-left')
.find_all('a', class_='footer-bar-action source')
na = "" if len(name) == 0 else name[0].text
# 評(píng)論數(shù)
num = itemTag.find('div', class_='bui-left footer-bar-left')
.find_all('a',class_='footer-bar-action source')
數(shù)據(jù)庫(kù)判斷插入或更新
@staticmethod
def isExistList(self, list):
try:
with connection.cursor() as cursor:
for item in list:
key = item[2]
cursor.execute(list_select_sql, (key))
result = cursor.fetchone()
if result is None:
self.db_operate(list_insert_sql, item)
else:
temp = (item[0], item[1], item[5], item[8], item[2])
self.db_operate(list_update_sql, temp)
finally:
# connection.close()
print('isExistList finally')
滾動(dòng)到底部的三種方式
# 滾動(dòng)到底部三種方式
# 1、driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 2当船、actions = ActionChains(driver)
# actions.move_to_element(e).perform()
elems = driver.find_elements_by_class_name("lazy-load-img")
driver.execute_script("arguments[0].scrollIntoView();", elems[len(elems) - 1])
# 停留三秒
time.sleep(3)
各種SQL語(yǔ)句
home_insert_sql = "INSERT INTO `tt_home_page` (`content`, `pic_url`,`click_key`,`create_time`,`type`) VALUES (%s,%s,%s,%s,%s)"
home_select_sql = "SELECT `*` FROM `tt_home_page` WHERE `click_key`=%s"
home_update_sql = "UPDATE tt_home_page SET content = %s, pic_url = %s WHERE click_key = %s"
list_insert_sql = "INSERT INTO `tt_home_list` (`content`, `pic_url`,`click_key`,`create_time`,`type`,`web_time`,`author_name`,`author_head`,`comment_num`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
list_select_sql = "SELECT `*` FROM `tt_home_list` WHERE `click_key`=%s"
list_update_sql = "UPDATE tt_home_list SET content = %s, pic_url = %s, web_time = %s, comment_num = %s WHERE click_key = %s"
獲取到的數(shù)據(jù)
- 首頁(yè)列表數(shù)據(jù)
- 首頁(yè)輪播數(shù)據(jù)
以上一個(gè)簡(jiǎn)單爬蟲(chóng)就完成了,很有意思~
具體項(xiàng)目可看Github,歡迎Star~