python之Selenium+pyquery爬取有大量反爬蟲的天眼查
天眼查:一個還有大量公司的資訊的網站。
所以反爬程度是相當高的,首先直接用requests.get(url)來獲取頁面原始碼,你會發現,明明顯示在頁面上的公司的一些資料都不在,他是利用其它的js的方法表達出來的,因為這個網站有專門的反爬蟲人員,可以在一些招聘網上看到工資還可以15k-30k
所以說用這些方法根本就不爬到什麼
那麼只有使出我們的殺手鐗,selenium,他的好處在於可以模擬瀏覽器操作,非常方便獲取屬性也很方便。
首先這個網站不登入的話,你會發現,怎麼原始碼上面的是和頁面表示出來的不一樣啊,明明是****公司**,在原始碼上卻是 @#¥····,連公司的基本資訊,比如郵箱什麼的,都是*****
所以首先我們註冊註冊一個天眼查的賬號:
接下來我們知道selenium驅動的瀏覽器是一個非常純淨的,沒有任何cookies,及一些資訊的儲存,目前來說是這樣,所以每一次訪問這個網站,都是全新的,沒有任何的登入資訊在上面,所以我們怎麼實現selenium模擬登入呢,這就要用到phantomjs,因為這個網站上面的登入註冊時用js程式碼生成的,原始碼上是沒有這些東西的,如果我們用phantomjs的話,可以直接解析出來所有js包含的html程式碼
下面一步一步來解析程式碼:
這是拼接完整的程式碼,keyword就是關鍵字,等會在main函式裡自行輸入,在search函式里加入phantomjs解析,這個要先安裝好phantomjs。
browser = webdriver.Chrome()
browser.maximize_window()#將瀏覽器最大化
wait = WebDriverWait(browser,10)
def search(keyword):
url_keyword = urllib.parse.quote(keyword) # 中文轉碼為url格式
url = 'http://www.tianyancha.com/search/' + url_keyword + '?checkFrom=searchBox'
driver = webdriver.PhantomJS(
executable_path='D:\\Program Files\\phantomjs-2.1.1-windows\\bin\\phantomjs') # phantomjs的絕對路徑
time.sleep(2)
driver.get(url)
browser.get(url)
return url
def main():
keyword = '阿里巴巴'
url = search(keyword)
if __name__ == '__main__':
main()
當我們執行程式碼後發現:怎麼回事啊,為什麼和我不加phantomjs程式碼不一樣啊,現在直接出現一個登陸的介面,需要登陸之後才能進入,這就是為什麼要註冊一個賬號的原因之一:
現在我們就需要利用selenuim模擬登入了,首先要做到的就是獲取輸入框,在剛剛這個介面按F12審查元素,再點選選擇元素的小箭頭,之後點選輸入手機號碼那裡,就可以在下面看到輸入框在原始碼中的位置,找到那個位置,右鍵,copy,selector,就可以得到他的這個元素的選擇器,因為我們用的是selenuim中一個查詢元素為位置的元素,具體看我的程式碼,之後用send_keys()輸入你的賬戶密碼,然後同樣的找到登入的那個位置的css_selector,再點選就進入了。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
def login():
try:
userInput = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb30.position-rel > input')))
passwordInput = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb40.position-rel > input')))
userInput.send_keys('*************')#賬號
passwordInput.send_keys('**********')#密碼
changeLoginWay = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.c-white.b-c9.pt8.f18.text-center.login_btn')))
changeLoginWay.click()
except TimeoutException:
login()
我們可以看到每個公司的class為search-result-single,
直接看程式碼:
這裡就要用到pyquery了,用它來解析公司的每一個資訊:具體pyquery使用方法就不詳談了,具體可以看我上一篇文章。
def get_company_info():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.search-block .result-list .search-result-single')))
html = browser.page_source#獲取此時頁面原始碼
doc = pq(html)
items = doc('.search-block .result-list .search-result-single').items()#解析到每一個公司的位置
for item in items:
company = {
'urlInfo':item.find('.name ').attr('href'),#公司連結
'name' : item.find('.name').text(),#名字
'LegalRepresentative':item.find('.info .title a').text(),#法人
'registerMoney':item.find('.info .title span').eq(0).text(),#註冊資金
'registerTime':item.find('.info .title span').eq(1).text(),#註冊時間
'tel':item.find('.contact .link-hover-click').eq(0).text(),#電話
'email':item.find('.contact .link-hover-click').eq(1).text(),#郵箱
'LegalPersonInfo':item.find('.content .match span').eq(1).text()#商標資訊
}
現在到了最關鍵的一步,就是翻頁,因為有很多頁,目前不是vip只有5頁可以查詢
下面是selenuim關於翻頁的操作:這裡面有很多坑,當時也折騰我了好久,
下面我來一一分析,當他在第一頁的時候,下面有個企業認證的廣告,剛好把翻頁的按鈕擋住了,當時這個bug我調了好久才找到,我們就用剛剛介紹的元素選擇器把它關掉就行了,把它關掉才可以點選下一頁那個按鈕,
第二個坑出現了,居然第一頁的下一步的按鈕和第二頁第三頁的selector不一樣,這裡也調了很久,程式碼裡可以看到我寫了判斷,最後再**執行get_company_info()**獲取資訊就行了。main裡面的那個迴圈就是用來翻頁的,從1到5頁。
move_to_bottom是用來翻到網頁最下面的。
def move_to_bottom():
js = "var q=document.documentElement.scrollTop=100000"
browser.execute_script(js)
def next_page(page_number):
print('------------------------------------正在爬取',page_number,'頁-----------------------------------------------------------------')
try:
if page_number == 2:
closeAdvertisement = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#tyc_banner_close')))
closeAdvertisement.click()
move_to_bottom()
if page_number == 2:
nextPageButton = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div.container-left > div.search-block > div.result-footer > div:nth-child(1) > ul > li:nth-child(12) > a')))
nextPageButton.click()
if page_number > 2:
nextPageButton = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div.container-left > div.search-block > div.result-footer > div:nth-child(1) > ul > li:nth-child(13) > a')))
nextPageButton.click()
get_company_info()
time.sleep(3)
except TimeoutException:
next_page(page_number)
def main():
keyword = '阿里巴巴'
url = search(keyword)
login()
for page in range(2,6):
next_page(page)
browser.close()
最後儲存到mongodb:
在get_company_info()方法裡呼叫就行了。
import pymongo
mongoclient = pymongo.MongoClient("localhost",port=27017,connect = False)
db = mongoclient .AugEleventh
classname = db.alibaba
def save_to_mongo(result):
if classname.insert(result):
print('儲存到mongoDB成功',result)
else:
print('儲存到mongoDb失敗')
這裡告訴大家基本以及爬完了,你想爬什麼公司的在keyword中輸入就可以了,但是不是vip只有最多5頁的內容。這個不用vip獲取更多公司資訊就說了,畢竟人家要靠這個賺錢,就放過他吧(其實是我完全不知道!!)
下面貼出完整程式碼:
from selenium import webdriver
import urllib
from pyquery import PyQuery as pq
import json
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
import time
import pymongo
mongoclient = pymongo.MongoClient("localhost",port=27017,connect = False)
db = mongoclient .AugEleventh
classname = db.alibaba
browser = webdriver.Chrome()
browser.maximize_window()#將瀏覽器最大化
wait = WebDriverWait(browser,10)
def move_to_bottom():
js = "var q=document.documentElement.scrollTop=100000"
browser.execute_script(js)
def search(keyword):
url_keyword = urllib.parse.quote(keyword) # 中文轉碼為url格式
url = 'http://www.tianyancha.com/search/' + url_keyword + '?checkFrom=searchBox'
driver = webdriver.PhantomJS(
executable_path='D:\\Program Files\\phantomjs-2.1.1-windows\\bin\\phantomjs') # phantomjs的絕對路徑
time.sleep(2)
driver.get(url)
browser.get(url)
return url
def get_total_page(url):
total = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#web-content > div > div.container-left > div.search-block > div.result-footer > div:nth-child(1) > ul > li:nth-child(11) > a')))
get_company_info()
return total.text
def login():
try:
userInput = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb30.position-rel > input')))
passwordInput = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb40.position-rel > input')))
userInput.send_keys('15995028879')
passwordInput.send_keys('19981027lcy')
changeLoginWay = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.c-white.b-c9.pt8.f18.text-center.login_btn')))
changeLoginWay.click()
except TimeoutException:
login()
def get_company_info():
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.search-block .result-list .search-result-single')))
html = browser.page_source
doc = pq(html)
items = doc('.search-block .result-list .search-result-single').items()
for item in items:
company = {
'urlInfo':item.find('.name ').attr('href'),
'name' : item.find('.name').text(),
'LegalRepresentative':item.find('.info .title a').text(),
'registerMoney':item.find('.info .title span').eq(0).text(),
'registerTime':item.find('.info .title span').eq(1).text(),
'tel':item.find('.contact .link-hover-click').eq(0).text(),
'email':item.find('.contact .link-hover-click').eq(1).text(),
'LegalPersonInfo':item.find('.content .match span').eq(1).text()
}
save_to_mongo(company)
def next_page(page_number):
print('------------------------------------正在爬取',page_number,'頁-----------------------------------------------------------------')
try:
if page_number == 2:
closeAdvertisement = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#tyc_banner_close')))
closeAdvertisement.click()
move_to_bottom()
if page_number == 2:
nextPageButton = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div.container-left > div.search-block > div.result-footer > div:nth-child(1) > ul > li:nth-child(12) > a')))
nextPageButton.click()
if page_number > 2:
nextPageButton = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#web-content > div > div.container-left > div.search-block > div.result-footer > div:nth-child(1) > ul > li:nth-child(13) > a')))
nextPageButton.click()
get_company_info()
time.sleep(3)
except TimeoutException:
next_page(page_number)
def save_to_mongo(result):
if classname.insert(result):
print('儲存到mongoDB成功',result)
else:
print('儲存到mongoDb失敗')
def main():
keyword = '阿里巴巴'
url = search(keyword)
login()
total_pages = int(get_total_page(url)[-3:])#獲取下他的總頁數,但是沒用,因為不是vip只能爬5頁,本來我不是想吧下面那個6換成total_pages 的
for page in range(2,6):
next_page(page)
browser.close()
if __name__ == '__main__':
main()
目前的我的模擬登入不是最好的,還有種是直接利用登入後的cookies資訊,用selenuim登入後直接就是已經登陸的狀態,目前我還不怎麼清楚怎麼做,希望有大神在評論區說說。