Python爬蟲筆記技術篇

前言

本篇爲技術篇,,會講解各類爬蟲庫的使用,至於庫的安裝在安裝篇已經介紹了html

requests出現中文亂碼

這種狀況是網頁沒有設置編碼,獲取不到,因此使用了默認的編碼,這個時候中文就會出現亂碼的狀況python

只須要多加一行代碼便可git

response.encoding='gb2312'

使用代理

免費的代理我試着不行,暫時不研究了,寫一下付費的代理是怎麼使用的github

我購買的是訊代理,購買以後先在白名單裏面添加本身的IP,而後點擊生成APIweb

選擇訂單,選擇一個城市,而後生成jsonmongodb

接下來使用Python獲取代理IP,我是獲取了以後存到數據庫了chrome

import pyodbc
import json
import requests
import sys
import time


headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac 0S X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/52.0.2743.116 Safari/537.36'}
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=192.168.3.8,1433;DATABASE=VaeDB;UID=sa;PWD=test123')
cursor = conn.cursor()
r = requests.get('http://apXXXXXXXXXXXXXXXXXXXXX40300', headers=headers)
print(r.text)
jsonobj = json.loads(str(r.text))

datetime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

cursor.execute(
    'update ProxyIP set IP=?,UpdateDate=? where Id=1', (jsonobj['RESULT'][0]['ip']+':'+jsonobj['RESULT'][0]['port'],datetime))
conn.commit()
sys.exit()

怎麼使用代理,這個分爲好幾個狀況,我使用的是Selenium,就寫這個,requests的用到再補充數據庫

conn = pyodbc.connect(
    'DRIVER={SQL Server};SERVER=111.108.8.2,1433;DATABASE=VaeDB;UID=sa;PWD=testxxxx')

cursor = conn.cursor()
cursor.execute("""
select IP from dbo.ProxyIP
"""
)
data = cursor.fetchone()
proxyip=str(data[0])
chrome_options=webdriver.ChromeOptions()
chrome_options.add_argument('--proxy-server=http://'+ proxyip)
browser = webdriver.Chrome(chrome_options=chrome_options)

BeautifulSoup的使用

我使用BeautifulSoup爬取了好幾萬的數據了,對於普通的網站,BeautifulSoup真的很好用json

#BeautifulSoup初始化能夠自動更正HTML格式,補全沒有閉合的元素
print (soup.prettify())#以標準的縮進格式輸出
print(soup.title)#標題
print(soup.title.string)#標題裏面的內容
print(soup.title.name)#title的節點名稱,就是title
print(soup.p)#第一個p元素的內容
print(soup.p.attrs)#第一個p元素的全部屬性和值
print(soup.p['class'])#第一個p元素class屬性的值
print(soup.p['name'])#第一個p元素name屬性的值
print(soup.p.b.string)#第一個p標籤下的b標籤的文本內容
print(soup.p.contents)#第一個p元素下的全部子節點,不包括孫子節點
#第一個p元素全部的子節點
print(soup.p.descendants)
for i,child in enumerate(soup.p.descendants):
    print(i,child)

print(soup.p.parent)#第一個p元素的父節點
#第一個p元素全部的父節點
print(soup.p.parents)
print(list(enumerate(soup.p.parents)))

print(soup.p.next_sibling)#第一個p元素的下一個兄弟節點,注意有回車的時候要寫兩個next_sibling
print(list(enumerate(soup.p.next_siblings)))#第一個p元素後面的全部兄弟節點
print(soup.p.previous_sibling)#第一個p元素的上一個兄弟節點
print(list(enumerate(soup.p.previous_siblings)))#第一個p元素前面的全部兄弟節點

#########################################################
#下面這些是比較經常使用的,上面的瞭解一下便可

# 判斷某個標籤是否有屬性,例如img標籤有一個alt屬性,有時候img沒有alt屬性,我就能夠判斷一下,不然出錯
if img.attrs.get('alt'):

soup.find(id='text-7').find_all(name='li')
#根據文本查找到該標籤
# 例以下面的,根據Description查找含有Description的第一個p元素
test = soup.find(lambda e: e.name == 'p' and 'Description' in e.text)
# 其實若是是直接子元素的話,也可使用parent,可是這個不多用,適用狀況很少
test= soup.find(text=re.compile('Description')).parent

#查找某個屬性爲包含的標籤
#標籤的屬性有不少值,例如img標籤的alt屬性,有item和img兩個值,能夠經過以下查找
noscript.find_all('img',attrs={'alt':re.compile('item')})

#判斷屬性裏面是否有某個值
if 'Datasheet' in img['alt']:

#替換全部的br換行符號
html = get_one_page(url)
    return html.replace('<br>', '').replace('<br />', '').replace('<br/>', '')

#去除最後一個逗號
datasheet_url.rstrip(',')

#去除關鍵字和空格,只要後面的內容
#例如 Function : Sensitive Gate Silicon Controlled Rectifiers
#獲得的就是Sensitive Gate Silicon Controlled Rectifiers
return re.sub(keywords+'.*?[\s]:.*?[\s]', '', child.find(text=re.compile(keywords)).string)

#返回某個符號以前的字符
import re

text="K6X4008C1F-BF55 ( 32-SOP, 55ns, LL )"

b=re.search('^[^\(]*(?=\()',text,re.M)
if b:
    print(b.group(0))
    print(len(b.group(0)))
else:
    print('沒有')
    
#關鍵地方是,這裏是匹配的(  括號須要\來轉義一下    
^[^\(]*(?=\()
#若是是逗號,能夠寫        
^[^,]*(?=,)
#若是是單詞,好比我想匹配Vae這個單詞,以下
text='XuSong Vae hahaha'
text2='VV Vae hahaha'
b=re.search('^[^Vae]*(?=Vae)',text,re.M)        
#這個例子很重要,text是能夠正則出XuSong的,可是下面的VV就正則不出來了,由於^是後面的Vae的任意一個單詞,只要前面包含就不行,VV包含了V,因此就不行了,我嘗試着給Vae加括號,也不行.而後我就想了一個辦法,把Vae替換成逗號之類的符號不就能夠了,只要是一個字符就行,以下
text='XuSong Vae hahaha'
text2='VV Vae hahaha'
b=re.search('^[^,]*(?=,)',text.replace('Vae',','),re.M)    

#一段HTML元素中去除a標籤,可是保留a標籤的值
return re.sub('(<\/?a.*?>)', '', description_element)

#有時候想獲取一段HTML元素內容,由於有的排版在,好比ul和li元素,排版是在的,若是使用text就是一串文本,換行都沒了,能夠這樣
str(child.find(class_='ul2'))   #獲取到這段HTML元素以後,使用str函數變成字符串便可

#下一個兄弟元素最好使用find_next_sibling()
#等待驗證,和next_sibling比較一下再說
驗證完畢,我來說一下find_next_sibling()和next_sibling的區別
若是想要後面的元素的話,寫find_next_sibling()
若是想要後面的內容的話,寫next_sibling
例如
<a>111</a><p>222</p>   想要獲取p元素應該使用find_next_sibling()
<a>111</a>我是文本        想要獲取 我是文本 應該使用next_sibling

#Python爬蟲數據插入到MongoDB
import pymongo
client = pymongo.MongoClient("mongodb://admin:test123@192.168.3.80:27017/")
db = client.datasheetcafe
collection = db.datasheetcafe
collection.insert_one(message)

Selenium的使用

在爬取一個新網站的時候,我發現網站上的網頁數據全都是動態加載的,瀏覽器加載以後數據纔會顯示,這個時候BeautifulSoup就沒用了,徹底獲取不到HTML節點

這種狀況,可使用Selenium進行動態加載,我使用這個已經爬取了近200萬的數據

基礎使用

#有不顯示瀏覽器的,可是我選擇了Chrome瀏覽器
browser = webdriver.Chrome()
#先獲取url,再選擇元素
browser.get(url)
div = browser.find_element_by_css_selector('.information')
#find_element_by_css_selector這個東西是css選擇器,若是選擇一個就使用這個,想要選擇一堆就加個s,使用find_elements_by_css_selector
#後面的類就是. id就是# 標籤名就直接寫,以下
table = browser.find_element_by_css_selector('#part-specs') 
table.find_elements_by_css_selector('tr')
# 獲取屬性的值
tr.get_attribute('class')
#對了,下面這個獲取的可不是HTML元素,是一個WebElement元素
table = browser.find_element_by_css_selector('#part-specs')
#因此若是你想要HTML元素這樣寫
table = browser.find_element_by_css_selector('#part-specs').get_attribute('outerHTML')
#獲取裏面的文本值就這樣寫
browser.find_element_by_css_selector('.part-number').text
#至於怎麼判斷元素是否存在的,我寫了if可是沒有,因此我利用try catch幫助解決
try:
    button=browser.find_element_by_css_selector('#show-secondary-part-list')
    button.click()
except Exception as e:
    print('沒有這個元素')

Selenium加載時間過長

有時候Selenium加載一個網頁時間過長了,因此必須設定一個超時時間

browser = webdriver.Chrome()
browser.set_page_load_timeout(20)
browser.set_script_timeout(20)

try:
    browser.get(address)
except TimeoutException:
    browser.execute_script('window.stop()')
    
div = browser.find_element_by_css_selector('.information') 
....

先設定加載時間爲20秒,若是20都沒加載出來,就算了,直接中止加載,爬取網頁內容吧,若是一個HTML元素都沒抓取到,空白頁面,那就try catch跳過這個網頁

Selenium使用Chrome,隱藏Chrome

默認使用Chrome是加載出來的,也能夠隱藏Chrome瀏覽器,那個無界面PhantomJS已經被淘汰了

chrome_options=webdriver.ChromeOptions()
# chrome_options.add_argument('--headless') 若是想不彈出chrome瀏覽器就開啓這兩行,那個PantomJS啥的已通過期了
# chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--proxy-server=http://'+ proxyip)
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation']) #這一行是爲了防止網站識別出我是selenium,參考:https://zhuanlan.zhihu.com/p/65077940
browser = webdriver.Chrome(chrome_options=chrome_options)

多進程下沒法退出exe

個人爬蟲爬了一段時間就中止了,selenium控制的瀏覽器要麼變成了空白頁,要麼訪問失敗,最可怕的是頁面卡着不動了,這個時候只能重啓爬蟲程序了,因此我把爬蟲發佈成exe了,我使用Windows自帶的計劃任務,隔一段時間就啓動exe爬蟲,而後問題來了

我必須關閉exe的彈窗,否則加載愈來愈多的exe,內存會崩的,因而我採用了Python多進程

一個進程去爬蟲,一個進程去計時,若是計時10分鐘,就退出exe

可是沒有執行,不管我使用sys.exit()仍是os._exit()都沒法退出exe,至今不知道爲何

沒辦法只好採起了另一種方法,殺進程

import os

os.system('taskkill /im conhost.exe /F')
# 這兩個不能同時執行,我寫了兩個py,發佈兩個exe執行
os.system('taskkill /im chromedriver.exe /F')
os.system('taskkill /im chrome.exe /F')

我把控制檯和Chrome全殺了.......這樣Windows計劃任務會重啓exe,而後過10分鐘我再全殺了.....

對了,Win10的計劃任務也搞了我很久,就是不成功,詳情見Windows計劃任務

scrapy

暫留......

scrapy startproject tutorial

scrapy genspider quotes quotes.toscrape.com

scrapy crawl quotes

爬蟲小Demo

爬蟲小Demo應該不會再更新了,我爬取的東西不可能寫出來了,僅僅介紹技術,授人以漁吧

爬取知乎發現頁面的今日最熱

import requests
import re
headers = {'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac 0S X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/52.0.2743.116 Safari/537.36'}
r =requests.get("https://www.zhihu.com/explore", headers=headers)
pattern = re.compile('explore-feed.*?question_link.*?>(.*?)</a>', re.S)
titles = re.findall(pattern,r.text)
print(titles)

講解:headers裏面有瀏覽器標識,不加這個知乎會禁止抓取

爬取某張圖片

import requests
import re
headers = {'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac 0S X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/52.0.2743.116 Safari/537.36'}
r =requests.get("https://avatars0.githubusercontent.com/u/13572737?s=460&v=4", headers=headers) 
with open('Vae.jpg','wb') as f:
    f.write(r.content)

這個不只能夠爬取圖片,爬取視頻,音頻,也是這樣的
==注意:爬取圖片的時候,不寫headers會報錯,找不到源==
下面是把圖片保存到制定位置的代碼,多了一個判斷文件夾是否存在,不存在就建立文件夾的操做,我是根據圖片的連接截取做爲文件夾的名稱的,使用建立文件夾的os須要導入os

import os
def get_allpath(imgurl):
    info=imgurl[imgurl.index('uploads'):]
    infos=info.split('/')
    return infos[0]+"\\"+infos[1]+infos[2]+"\\"+infos[3]

def get_path(imgurl):
    info=imgurl[imgurl.index('uploads'):]
    infos=info.split('/')
    return infos[0]+"\\"+infos[1]+infos[2]

def create_makedirs(dirpath):
    if not os.path.exists(dirpath):
        os.makedirs(dirpath)

def get_image(child, path):
    for img in child.find_all(name='img'):
        imgurl = img.attrs.get('data-lazy-src')
        if imgurl:
            if 'gif' in imgurl:
                create_makedirs(path+get_path(imgurl))
                r = requests.get(imgurl,headers=headers)
                with open(path+get_allpath(imgurl), 'wb') as f:
                    f.write(r.content)
                    
       #最後我在調用的時候,直接輸入放到哪裏的路徑便可             
            path = 'D:\\datasheetcafe\\'
            get_image(child, path)

爬取視頻

其實和爬取圖片是同樣的,只不過換了url而已,這裏以爬取個人嗶哩嗶哩視頻爲例

如圖是個人嗶哩嗶哩發的一個視頻,點擊F12,而後在NetWork裏面找到視頻的那個請求,通常是最大Size的那個

點進去,看到的那一串就是視頻地址

複製視頻地址到python爬蟲裏面,改一下存儲爲.mp4

import requests
import re
headers = {'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac 0S X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/52.0.2743.116 Safari/537.36'}
r =requests.get("https://113-219-141-2.ksyungslb.com/upos-sz-mirrorks32u.acgvideo.com/upgcxcode/63/76/19157663/19157663-1-48.mp4?e=ig8euxZM2rNcNbKVhwdVhoMMhwdVhwdEto8g5X10ugNcXBlqNxHxNEVE5XREto8KqJZHUa6m5J0SqE85tZvEuENvNC8xNEVE9EKE9IMvXBvE2ENvNCImNEVEK9GVqJIwqa80WXIekXRE9IMvXBvEuENvNCImNEVEua6m2jIxux0CkF6s2JZv5x0DQJZY2F8SkXKE9IB5QK==&deadline=1562826409&gen=playurl&nbs=1&oi=1947754487&os=ks3u&platform=pc&trid=28dcba5166d84f6f8b078fccbdd41f2e&uipk=5&upsig=cae257a7f3504f28137a3036304288df&uparams=e,deadline,gen,nbs,oi,os,platform,trid,uipk&mid=32059965&ksy_gslb_referer=https%3A%2F%2Fwww.bilibili.com%2Fvideo%2Fav11592898", headers=headers) 
with open('Vae.mp4','wb') as f:
    f.write(r.content)

網頁數量少的動態網站的爬蟲

網站介紹

這個網站是這樣的,他的信息是js動態加上去的,並且必須登陸以後才能看到數據

因此我使用BeautifulSoup在線爬不行,我不會

使用了Selenium登陸了,也動態加載頁面了,數據也出來了,可是這個網站特別的不規則,

都沒有class,我很差找規律,也是不會寫......

解決辦法

大佬給我提出個辦法,由於這個網站的頁面很少,也就20幾個,讓我直接保存到本地,而後讀取本地的html爬蟲,這樣就可使用BeautifulSoup了,不錯哦

個人智障作法

我直接在網頁上按下了ctrl+s,保存到了本地.........

注意啊!! ctrl+s保存的網頁仍是沒有數據的啊,仍是須要js加載的啊......我忙活了半天,白忙活了

正確的作法

大佬得知此事以後,痛心疾首,說我早就和你說了,複製DOM就能夠了,你不聽 🐷

對此我只能說,我是🐷,我是🐷,我是🐷

正確的作法是,選擇這該死的DOM,右鍵,複製HTML,這樣他的數據啥的,全都有

我是一個一個複製了,而後保存到個人本地html了

若是是不少的話,成百上千的網頁,這樣就不適合手動了,可使用Selenium加載以後保存到本地

python爬蟲代碼

我不會放出全部的,寫寫重點

爬蟲爬本地HTML

首先要安裝一個爬本地HTML的包

pip install requests-file
from requests_file import FileAdapter

def get_one_page(file_name):
    s = requests.Session()
    s.mount('file://', FileAdapter())
    html = s.get(f'file:///D:/'+file_name+'.html')
    soup = BeautifulSoup(html, 'lxml')
    ...省略...

參考文章

相關文章
相關標籤/搜索