終於想開始爬自己想爬的網站了。於是就試着爬P站試試手。
我爬的圖的目標網址是: http://www.pixiv.net/search.php?word=%E5%9B%9B%E6%9C%88%E3%81%AF%E5%90%9B%E3%81%AE%E5%98%98,目標是將每一頁的圖片都爬下來。
一開始以為不用登陸,就直接去爬圖片了。
后來發現是需要登錄的,但是不會只好去學模擬登陸。
這里是登陸網站 https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index 的headers,
然后還要去獲取我們登陸時候需要的data。點住上面的presevelog,找到登陸的網址,點開查看Form Data就可以知道我們post的時候的data需要什么了。這里可以看到有個postkey,多試幾次可以發現這個是變化的,即我們要去捕獲它,而不能直接輸入。
於是退回到登陸界面,F12查看源碼,發現有一個postkey,那么我們就可以寫一個東西去捕獲它,然后把它放到我們post的data里面。
這里給出登陸界面需要的代碼:
1 def __init__(self): 2 self.base_url = 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index' 3 self.login_url = 'https://accounts.pixiv.net/api/login?lang=zh' 4 self.target_url = 'http://www.pixiv.net/search.php?' \ 5 'word=%E5%9B%9B%E6%9C%88%E3%81%AF%E5%90%9B%E3%81%AE%E5%98%98&order=date_d&p=' 6 self.main_url = 'http://www.pixiv.net' 7 # headers只要這兩個就可以了,之前加了太多其他的反而爬不上 8 self.headers = { 9 'Referer': 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index', 10 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) ' 11 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' 12 } 13 self.pixiv_id = 'userid' 14 self.password = '*****' 15 self.post_key = [] 16 self.return_to = 'http://www.pixiv.net/' 17 self.load_path = 'D:\psdcode\Python\pixiv_pic' 18 self.ip_list = [] 19 20 def login(self): 21 post_key_html = se.get(self.base_url, headers=self.headers).text 22 post_key_soup = BeautifulSoup(post_key_html, 'lxml') 23 self.post_key = post_key_soup.find('input')['value'] 24 # 上面是去捕獲postkey 25 data = { 26 'pixiv_id': self.pixiv_id, 27 'password': self.password, 28 'return_to': self.return_to, 29 'post_key': self.post_key 30 } 31 se.post(self.login_url, data=data, headers=self.headers)
愉快地解決完登陸問題之后,就可以開始爬圖片啦。
進入target_url:上面的目標網址。
點擊目標的位置
點開ul這個標簽,發現圖片全部都是在<li class="image-item">這里面的,因為我們要爬大一點的圖(爬個小圖有什么用啊!),所以還要進入一層第一個鏈接的網址去獲取大圖,我們可以發現我們只要在main_url((http://www.pixiv.net)),再加上第一個href,就可以跑到圖片所在的網址了,於是我們先跳轉到圖片網址看看怎么提取圖片。
發現圖片就躺在這里了,而且連標題都有,直接方便了我們存圖的名字了。於是我們就可以直接去提取圖片了。
注意我們在請求獲取圖片的時候要加一個referer,否則會403的。referer的找法就和上面一樣。
1 def get_img(self, html, page_num): 2 li_soup = BeautifulSoup(html, 'lxml') # 傳入第page_num頁的html 3 li_list = li_soup.find_all('li', attrs={'class', 'image-item'}) # 找到li所在位置 4 # print('get_list succeed') 5 # print(li_list) 6 for li in li_list: 7 href = li.find('a')['href'] # 直接提取第一個href 8 # print('get_href succeed') 9 # print(href) 10 jump_to_url = self.main_url + href # 跳轉到目標的url 11 # print('get_jump_to_url succeed') 12 jump_to_html = self.get_html(jump_to_url, 3).text # 獲取圖片的html 13 # print('get_jump_to_html succeed') 14 15 img_soup = BeautifulSoup(jump_to_html, 'lxml') 16 img_info = img_soup.find('div', attrs={'class', 'works_display'})\ 17 .find('div', attrs={'class', '_layout-thumbnail ui-modal-trigger'}) 18 # 找到目標位置的信息 19 if img_info is None: # 有些找不到url,如果不continue會報錯 20 continue 21 self.download_img(img_info, jump_to_url, page_num) # 去下載這個圖片 22 23 def download_img(self, img_info, href, page_num): 24 title = img_info.find('img')['alt'] # 提取標題 25 src = img_info.find('img')['src'] # 提取圖片位置 26 src_headers = self.headers 27 src_headers['Referer'] = href # 增加一個referer,否則會403,referer就像上面登陸一樣找 28 try: 29 html = requests.get(src, headers=src_headers) 30 img = html.content 31 except: # 有時候會發生錯誤導致不能獲取圖片.直接跳過這張圖吧 32 print('獲取該圖片失敗') 33 return False
接下來輪到下載圖片了。這個之前還不怎么會,臨時學了一下。
首先是創建文件夾,我這里是每一頁就開一個文件夾。
1 def mkdir(self, path): 2 path = path.strip() 3 is_exist = os.path.exists(os.path.join(self.load_path, path)) 4 if not is_exist: 5 print('創建一個名字為 ' + path + ' 的文件夾') 6 os.makedirs(os.path.join(self.load_path, path)) 7 os.chdir(os.path.join(self.load_path, path)) 8 return True 9 else: 10 print('名字為 ' + path + ' 的文件夾已經存在') 11 os.chdir(os.path.join(self.load_path, path)) 12 return False
1 def download_img(self, img_info, href, page_num): 2 title = img_info.find('img')['alt'] # 提取標題 3 src = img_info.find('img')['src'] # 提取圖片位置 4 src_headers = self.headers 5 src_headers['Referer'] = href # 增加一個referer,否則會403,referer就像上面登陸一樣找 6 try: 7 html = requests.get(src, headers=src_headers) 8 img = html.content 9 except: # 有時候會發生錯誤導致不能獲取圖片.直接跳過這張圖吧 10 print('獲取該圖片失敗') 11 return False 12 13 title = title.replace('?', '_').replace('/', '_').replace('\\', '_').replace('*', '_').replace('|', '_')\ 14 .replace('>', '_').replace('<', '_').replace(':', '_').replace('"', '_').strip() 15 # 去掉那些不能在文件名里面的.記得加上strip()去掉換行 16 17 if os.path.exists(os.path.join(self.load_path, str(page_num), title + '.jpg')): 18 for i in range(1, 100): 19 if not os.path.exists(os.path.join(self.load_path, str(page_num), title + str(i) + '.jpg')): 20 title = title + str(i) 21 break 22 # 如果重名了,就加上一個數字 23 print('正在保存名字為: ' + title + ' 的圖片') 24 with open(title + '.jpg', 'ab') as f: 25 f.write(img) 26 print('保存該圖片完畢')
這樣我們的大體工作就做完了。剩下的是寫一個work函數讓它開始跑。
1 def work(self): 2 self.login() 3 for page_num in range(1, 51): # 太多頁了,只跑50頁 4 path = str(page_num) # 每一頁就開一個文件夾 5 self.mkdir(path) # 創建文件夾 6 # print(self.target_url + str(page_num)) 7 now_html = self.get_html(self.target_url + str(page_num), 3) # 獲取頁碼 8 self.get_img(now_html.text, page_num) # 獲取圖片 9 print('第 {page} 頁保存完畢'.format(page=page_num)) 10 time.sleep(2) # 防止太快被反
啟動!
大概跑了10頁之后,會彈出一大堆信息什么requests不行怎么的。問了下別人應該是被反爬了。
於是去搜了一下資料,http://cuiqingcai.com/3256.html,照着他那樣寫了使用代理的東西。(基本所有東西都在這學的)。
於是第一個小爬蟲就好了。不過代理的東西還沒怎么懂,到時候看看,50頁爬了兩個多鍾。
對了。可能網站的源代碼會有改動的。因為我吃完飯后用吃飯前的代碼繼續工作的時候出錯了,然后要仔細觀察重新干。
1 # -*- coding:utf-8 -*- 2 import requests 3 from bs4 import BeautifulSoup 4 import os 5 import time 6 import re 7 import random 8 9 se = requests.session() 10 11 12 class Pixiv(): 13 14 def __init__(self): 15 self.base_url = 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index' 16 self.login_url = 'https://accounts.pixiv.net/api/login?lang=zh' 17 self.target_url = 'http://www.pixiv.net/search.php?' \ 18 'word=%E5%9B%9B%E6%9C%88%E3%81%AF%E5%90%9B%E3%81%AE%E5%98%98&order=date_d&p=' 19 self.main_url = 'http://www.pixiv.net' 20 # headers只要這兩個就可以了,之前加了太多其他的反而爬不上 21 self.headers = { 22 'Referer': 'https://accounts.pixiv.net/login?lang=zh&source=pc&view_type=page&ref=wwwtop_accounts_index', 23 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) ' 24 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' 25 } 26 self.pixiv_id = 'userid' 27 self.password = '*****' 28 self.post_key = [] 29 self.return_to = 'http://www.pixiv.net/' 30 self.load_path = 'D:\psdcode\Python\pixiv_pic' 31 self.ip_list = [] 32 33 def login(self): 34 post_key_html = se.get(self.base_url, headers=self.headers).text 35 post_key_soup = BeautifulSoup(post_key_html, 'lxml') 36 self.post_key = post_key_soup.find('input')['value'] 37 # 上面是去捕獲postkey 38 data = { 39 'pixiv_id': self.pixiv_id, 40 'password': self.password, 41 'return_to': self.return_to, 42 'post_key': self.post_key 43 } 44 se.post(self.login_url, data=data, headers=self.headers) 45 46 def get_proxy(self): 47 html = requests.get('http://haoip.cc/tiqu.htm') 48 ip_list_temp = re.findall(r'r/>(.*?)<b', html.text, re.S) 49 for ip in ip_list_temp: 50 i = re.sub('\n', '', ip) 51 self.ip_list.append(i.strip()) 52 print(i.strip()) 53 54 ''' 會被反爬,改成使用代理 55 def get_tml(self, url): 56 response = se.get(url, headers=self.headers) 57 return response 58 ''' 59 def get_html(self, url, timeout, proxy=None, num_entries=5): 60 if proxy is None: 61 try: 62 return se.get(url, headers=self.headers, timeout=timeout) 63 except: 64 if num_entries > 0: 65 print('獲取網頁出錯,5秒后將會重新獲取倒數第', num_entries, '次') 66 time.sleep(5) 67 return self.get_html(url, timeout, num_entries = num_entries - 1) 68 else: 69 print('開始使用代理') 70 time.sleep(5) 71 ip = ''.join(str(random.choice(self.ip_list))).strip() 72 now_proxy = {'http': ip} 73 return self.get_html(url, timeout, proxy = now_proxy) 74 else: 75 try: 76 return se.get(url, headers=self.headers, proxies=proxy, timeout=timeout) 77 except: 78 if num_entries > 0: 79 print('正在更換代理,5秒后將會重新獲取第', num_entries, '次') 80 time.sleep(5) 81 ip = ''.join(str(random.choice(self.ip_list))).strip() 82 now_proxy = {'http': ip} 83 return self.get_html(url, timeout, proxy = now_proxy, num_entries = num_entries - 1) 84 else: 85 print('使用代理失敗,取消使用代理') 86 return self.get_html(url, timeout) 87 88 def get_img(self, html, page_num): 89 li_soup = BeautifulSoup(html, 'lxml') # 傳入第page_num頁的html 90 li_list = li_soup.find_all('li', attrs={'class', 'image-item'}) # 找到li所在位置 91 # print('get_list succeed') 92 # print(li_list) 93 for li in li_list: 94 href = li.find('a')['href'] # 直接提取第一個href 95 # print('get_href succeed') 96 # print(href) 97 jump_to_url = self.main_url + href # 跳轉到目標的url 98 # print('get_jump_to_url succeed') 99 jump_to_html = self.get_html(jump_to_url, 3).text # 獲取圖片的html 100 # print('get_jump_to_html succeed') 101 102 img_soup = BeautifulSoup(jump_to_html, 'lxml') 103 img_info = img_soup.find('div', attrs={'class', 'works_display'})\ 104 .find('div', attrs={'class', '_layout-thumbnail ui-modal-trigger'}) 105 # 找到目標位置的信息 106 if img_info is None: # 有些找不到url,如果不continue會報錯 107 continue 108 self.download_img(img_info, jump_to_url, page_num) # 去下載這個圖片 109 110 def download_img(self, img_info, href, page_num): 111 title = img_info.find('img')['alt'] # 提取標題 112 src = img_info.find('img')['src'] # 提取圖片位置 113 src_headers = self.headers 114 src_headers['Referer'] = href # 增加一個referer,否則會403,referer就像上面登陸一樣找 115 try: 116 html = requests.get(src, headers=src_headers) 117 img = html.content 118 except: # 有時候會發生錯誤導致不能獲取圖片.直接跳過這張圖吧 119 print('獲取該圖片失敗') 120 return False 121 122 title = title.replace('?', '_').replace('/', '_').replace('\\', '_').replace('*', '_').replace('|', '_')\ 123 .replace('>', '_').replace('<', '_').replace(':', '_').replace('"', '_').strip() 124 # 去掉那些不能在文件名里面的.記得加上strip()去掉換行 125 126 if os.path.exists(os.path.join(self.load_path, str(page_num), title + '.jpg')): 127 for i in range(1, 100): 128 if not os.path.exists(os.path.join(self.load_path, str(page_num), title + str(i) + '.jpg')): 129 title = title + str(i) 130 break 131 # 如果重名了,就加上一個數字 132 print('正在保存名字為: ' + title + ' 的圖片') 133 with open(title + '.jpg', 'ab') as f: # 圖片要用b 134 f.write(img) 135 print('保存該圖片完畢') 136 137 def mkdir(self, path): 138 path = path.strip() 139 is_exist = os.path.exists(os.path.join(self.load_path, path)) 140 if not is_exist: 141 print('創建一個名字為 ' + path + ' 的文件夾') 142 os.makedirs(os.path.join(self.load_path, path)) 143 os.chdir(os.path.join(self.load_path, path)) 144 return True 145 else: 146 print('名字為 ' + path + ' 的文件夾已經存在') 147 os.chdir(os.path.join(self.load_path, path)) 148 return False 149 150 def work(self): 151 self.login() 152 for page_num in range(1, 51): # 太多頁了,只跑50頁 153 path = str(page_num) # 每一頁就開一個文件夾 154 self.mkdir(path) # 創建文件夾 155 # print(self.target_url + str(page_num)) 156 now_html = self.get_html(self.target_url + str(page_num), 3) # 獲取頁碼 157 self.get_img(now_html.text, page_num) # 獲取圖片 158 print('第 {page} 頁保存完畢'.format(page=page_num)) 159 time.sleep(2) # 防止太快被反 160 161 162 pixiv = Pixiv() 163 pixiv.work()