My blogs

The greatest test of courage on earth is to bear defeat without losing heart.

0%

selenium(三)

利用 Selenium,BeautifulSoup 對 IG,FB 爬取。
紀錄筆記


IG 搜尋關鍵字抓取圖片

  • 敘述
    自動化來抓取 IG 上關鍵字標籤圖片下載!

    =>ig 官方


Code

安裝

示範於 作業系統:windows 瀏覽器:Chrome
需先安裝:
第三方套件

  • wget

    • 使 pip install wget
  • selenium

    • 使 pip install selenium
  • webdriver

    • 需先查看瀏覽器版本

step1: 打開 Chrome 找到自訂及管理
step2: 找到說明點擊
step3: 找到關於Google Chrome點擊
step4: 查看版本
step4: 下載對應版本 ChromeDriver


載入套件
1
2
3
4
5
6
7
8
9
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import os
import wget
  • 程式透過呼叫 WebDriver 來直接對瀏覽器進行操作。
    WebDriver 只是一個 API 介面,實作則決定於所選用的瀏覽器 driver(本篇是以 Google Chrome)

  • 該 selenium.webdriver 模塊提供了所有的 webdriver 實現。當前支持的 WebDriver 實現有 Firefox、Chrome、IE 和
    Remote。該鍵在鍵盤像 RETURN,F1,ALT 等類提供鍵。
    作用可以來模擬鍵盤操作。

    => 參考 2.2 節 官方文件

  • Waits 作用於當網頁載入時需 時間等待,若直接進行爬取動作但網頁上未生成時會出現錯誤。

    => 參考 5.1 節 官方文件

  • os 最後要將圖片存入電腦,需要用到os來建立檔案夾放置檔案。

    => 用法參考 文件

  • wget 網路上進行下載的簡單而強大的自由軟體。


定義
1
2
3
4
5
path = ("you chromedriver.exe path")
driver = webdriver.Chrome(path)
# 前往特定網址
driver.get('https://www.instagram.com/')

提示 : 如是在檔案總管複製路徑需將\換成 /否者會出錯

把 chromedriver 檔案路徑傳入,由於執行瀏覽器需chromedriver.exe執行檔。

driver.get()表示指定要去的網址


登入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
username = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'username')))
password = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'password')))

username.clear()
password.clear()

username.send_keys('you account')
password.send_keys('you password')

login = driver.find_element_by_xpath(
'//*[@id="loginForm"]/div/div[3]/button/div')
login.click()


step1: 打開 網站首頁,點擊滑鼠右鍵。連結 =>ig 官方
step2: 找到檢查點擊

  • 點選左上藍色箭頭

    範例

  • 拉藍色箭頭點到所要的按鈕

    範例

  • 需等待到頁面挑轉好使用wait查看到輸入框帳號的框框,當中有個定義為name="username"取得這項類別,(By.NAME, 'username')

    由於找到name類別,就用by.NAME。這樣就能確定輸入帳號框框以生成完成,再進行輸入帳號動作。

    密碼地方同理就不做示範。

  • login 按下登入的地方,抓取此區塊定義find_element_by_xpath(),這邊抓的是xpath
    取得xpath,點選 上圖藍色選取線點選右鍵 => 找到copy點擊 => 找到 copyXPath點擊。

  • send_keys()送出。

複製 xpath 範例格式:

1
'//*[@id="loginForm"]/div/div[3]/button/div'

driver.find_element_by_xpath()取得 html 上 xpath 位置

  • 最後再進行click動作完成登入。

  • 提示 : username.clear()是怕輸入欄位上有提醒文字,所以保險先清空!


輸入查找關鍵字
1
2
3
4
5
6
7
8
9
10
11
waitsearch = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="react-root"]/section/nav/div[2]/div/div/div[2]/input')))

keyword = "#dog"
waitsearch.send_keys(keyword)
time.sleep(1)
waitsearch.send_keys(Keys.ENTER)
time.sleep(1)

waitsearch.send_keys(Keys.ENTER)

  • waitsearch一樣需等待搜尋框框出現。

  • keyword自行修改為搜尋標籤。

  • 這邊用到time模組,由於ig 搜尋需要按兩次enter,但是不能執行過快,而加入停留一秒後執行。


載入圖片
1
2
3
4
5
6
7
8
9
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'FFVAD')))

for s in range(10):
driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
time.sleep(4)

imgs = driver.find_elements_by_class_name("FFVAD")

  • WebDriverWait一樣需等待圖片出現後執行。

  • (By.CLASS_NAME, 'FFVAD')定位用class_NAME

    • 點選左上藍色箭頭到圖片上查看,找到class=FFVAD,就是圖片上class類別。
  • 下圖 :

    • 範例
  • driver.execute_script("window.scrollTo(0,document.body.scrollHeight)
    script為了載入更多照片,把視窗向下拉,document.body.scrollHeight拉到視窗高度最底。

  • PS:須給它時間載入,要停留幾秒加載。


下載圖片
1
2
3
4
5
6
7
8
9
10
11
imgpath = os.path.join(keyword)
os.mkdir(imgpath)
count = 1
for i in imgs:
save_as = os.path.join(imgpath, keyword + str(count)+".jpg")
# print(i.get_attribute("src"))
wget.download(i.get_attribute("src"), save_as)

count += 1


  • 啟用os.path.join

    • Python 中的方法會智能地連接一個或多個路徑組件。此方法將各個路徑組成部分與每個非空部分之後的
      最後一個路徑組成部分恰好用一個目錄分隔符(/)串聯在一起。如果要連接的最後一個路徑組件為空,則將目錄分隔符(‘/‘)放在末尾。
  • os.mkdir建立資料夾,以keyword名稱建立檔名。

  • save_askeyword加上數字來存檔名。

  • wget.download使套件進行下載,下載需要圖片 來源get_attribute("src")
    Html標籤上的找到src就有網址,得到後就能進行下載。


FB 抓取連結網址&連結標題


Code~

安裝~

示範於 作業系統:windows 瀏覽器:Chrome
需先安裝:
第三方套件

  • beautifulsoup4

    • 使 pip install beautifulsoup4

載入套件~
1
2
3
4
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time
  • Beautiful Soup 是一個 Python 的函式庫模組,可以讓開發者僅須撰寫非常少量的程式碼,
    就可以快速解析網頁 HTML 碼,從中翠取出使用者有興趣的資料、去蕪存菁,降低網路爬蟲程式的開發門檻、加快程式撰寫速度。

    => 參考 官方文件

  • Options options 物件,主要用途為取消網頁中的彈出視窗,避免妨礙網路爬蟲的執行,
    也可以不讓瀏覽器執行在前景,而是在背景執行(不讓我們肉眼看得見)。


定義~
1
2
3
4
5
6
7
8
options = Options()
options.add_argument("--disable-notifications")

path = ("you chromedriver.exe path")

driver = webdriver.Chrome(path, chrome_options=options)

driver.get("https://www.facebook.com/")
  • options 物件,主要用途為取消網頁中的彈出視窗,避免妨礙網路爬蟲的執行。。

  • options.add_argument("--disable-notifications")登入fb跳出通知,自動按下自動按允許

  • driver.get(url)得到去網址。


登入~
1
2
3
4
5
6
7
8
9
10
11
email = driver.find_element_by_id("email")
password = driver.find_element_by_id("pass")

email.send_keys('you account')
password.send_keys('you password')
password.submit()

time.sleep(3)
driver.get('https://www.facebook.com/AIRC.CJCU')
time.sleep(3)

step1: 打開 網站首頁,點擊滑鼠右鍵。連結 =>fb 官方
step2: 找到檢查點擊

  • 點選左上藍色箭頭
    範例

  • 拉藍色箭頭點到所要的按鈕
    範例

  • 查看到輸入框帳號的框框,當中有個定義為id="email"
    取得這項類別,driver.find_element_by_id("email")

    找到id類別,就用by_id。這樣就能確定輸入帳號框框。

    密碼地方同理就不做示範。

  • .submit()提交送出資訊。

  • 登入完成後driver.get(url)再進到要去的網址。


拉動視窗&取得原始碼&定義抓取資料
1
2
3
4
5
6
7
8
9
10
11
for x in range(5):
driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
time.sleep(3)

soup = BeautifulSoup(driver.page_source, 'html.parser')

titles = soup.find_all('span', {
'class': 'a8c37x1j ni8dbmo4 stjgntxs l9j0dhe7 ojkyduve'})

href = soup.find_all('a', {'class': 'l9j0dhe7'})

  • PS :for迴圈可以要取得較多資料而修改。

  • script() 把視窗向下拉,上方有較詳細說明 。

  • BeautifulSoup來抓取原始碼html.parser為解析器。

  • 示範抓title&href
    範例

  • titles使find_all(標籤),在 Html標籤上的找到titles所指定的,得到後就能抓下。

  • href也同理。


印出資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for title in titles:

post = title.find('span', {'dir': 'auto'})

if post:
print(post.getText())


print('------------------------------')

for i in href:

print(i.get('href'))

  • .getText()抓出文字。

結語

  • ig 有些BUG,當我測試更多照片下載,挑整for迴圈後,照片落在 50 張左右就不會再增加。
  • fb 抓取連結的部分,抓取定義部分,會抓到其他網頁中連結進來,目前尚有有 bug。

ig 修正 coding

  • 這邊可以達成下載多筆照片下來,但不是最好辦法。

  • 這邊bug在於會重複下載相同照片固定幾張

  • step : 下載圖片 => 刪除相同照片 => 批量修改檔名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import os
import wget

path = ("you driver.exe path ")
driver = webdriver.Chrome(path)
# 前往特定網址
driver.get('https://www.instagram.com/')
username = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'username')))
password = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'password')))
username.clear()
password.clear()

username.send_keys('you account')
password.send_keys('you password')

login = driver.find_element_by_xpath(
'//*[@id="loginForm"]/div/div[3]/button/div')
login.click()

waitsearch = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="react-root"]/section/nav/div[2]/div/div/div[2]/input')))

keyword = "#dog"
waitsearch.send_keys(keyword)
time.sleep(1)
waitsearch.send_keys(Keys.ENTER)
time.sleep(1)

waitsearch.send_keys(Keys.ENTER)

WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'FFVAD')))


# imgs = driver.find_elements_by_class_name("FFVAD")

imgpath = os.path.join(keyword)
os.mkdir(imgpath)
count = 1
for y in range(10):

driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
time.sleep(4)
imgs = driver.find_elements_by_class_name("FFVAD")

for i in imgs:

save_as = os.path.join(imgpath, keyword + str(count)+".jpg")
# print(i.get_attribute("src"))
wget.download(i.get_attribute("src"), save_as)

count += 1

  • 把相同照片刪除 coding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import os
import hashlib
import logging
import sys


def logger():
""" 獲取logger"""
logger = logging.getLogger()
if not logger.handlers:
# 指定logger輸出格式
formatter = logging.Formatter(
'%(asctime)s %(levelname)-8s: %(message)s')
# 檔案日誌
file_handler = logging.FileHandler("test.log")
file_handler.setFormatter(formatter) # 可以通過setFormatter指定輸出格式
# 控制檯日誌
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter # 也可以直接給formatter賦值
# 為logger新增的日誌處理器
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# 指定日誌的最低輸出級別,預設為WARN級別
logger.setLevel(logging.INFO)
return logger


def get_md5(filename):
m = hashlib.md5()
mfile = open(filename, "rb")
m.update(mfile.read())
mfile.close()
md5_value = m.hexdigest()
return md5_value


def get_urllist():
# 替換指定的資料夾路徑即可
base = ("D:\爬蟲\#이지은/")
list = os.listdir(base)
urlList = []
for i in list:
url = base + i
urlList.append(url)
return urlList


if __name__ == '__main__':
log = logger()
md5List = []
urlList = get_urllist()
for a in urlList:
md5 = get_md5(a)
if (md5 in md5List):
os.remove(a)
print("重複:%s" % a)
log.info("重複:%s" % a)
else:
md5List.append(md5)
# print(md5List)
print("一共%s張照片" % len(md5List))

參考教學


如果您喜歡我的文章,請幫我按五下 ,感謝大家。