主頁 > 後端開發 > Python爬蟲Request輪子工具

Python爬蟲Request輪子工具

2021-04-27 17:30:05 後端開發

SuperSpider

== 萬字長文,建議使用目錄點擊查閱,有助于高效開發,建議點贊收藏 ==

文章目錄

  • SuperSpider
    • Request抓取思路步驟
      • 多級頁面資料抓取思路
      • UserAgent反爬處理
      • Cookie反爬
        • Cookie引數使用
        • CookieJar物件轉換為Cookies字典
    • requests模塊引數總結
    • requests.get()
    • requests.post()
    • request.session()
        • 作用與應用場景
        • 使用方法
    • response
      • response.text 和response.content的區別:
    • 動態加載資料抓取-Ajax
    • json決議模塊
      • json.loads(json)
      • json.dump(python,f,ensure_ascii=False)
      • jsonpath
      • json模塊總結
    • 控制臺抓包
    • 代理設定
      • 定義及分類
      • 普通代理思路
      • 普通代理
      • 私密代理+獨享代理
      • 私密代理+獨享代理 - 示例代碼
      • 建立自己的代理IP池 - 開放代理 | 私密代理
    • 拉勾網阿布云代理
    • unicode與encode
    • 決議模塊總結
      • re正則決議
      • lxml+xpath決議
      • xpath運算式
    • 資料持久化
      • mysql
      • Mysql模板
      • mongodb
      • mongodb模板
      • Json
      • Json模板
      • json常用操作
      • json存盤串列
      • CSV模板
      • txt模板
      • redis增量URl爬蟲實作思路
    • 休眠設定
      • 時間引數
    • 打碼平臺
    • 云詞
    • 多執行緒爬蟲
      • 應用場景
      • 多執行緒爬蟲示例【豆瓣】
    • selenium+PhantomJS/Chrome/Firefox
      • selenium
      • 繞過selenium檢測
      • selenium對cookie的處理
        • 獲取cookie
        • 洗掉cookie
      • selenium使用代理ip
      • selenium替換user-agent
      • 指定埠遙控
      • PhantomJS瀏覽器
      • 百度示例代碼
      • 瀏覽器物件(browser)方法
      • Selenium 定位節點八種方法
      • 貓眼電影示例
      • chromedriver設定無界面模式
      • selenium - 滑鼠操作
      • selenium處理iframe反爬

Request抓取思路步驟

1】先確定是否為動態加載網站
【2】找URL規律
【3】正則運算式 | xpath運算式
【4】定義程式框架,補全并測驗代碼
  • 細節要點:查看頁面編碼charset、請求時是否需要驗證verify=FALSE

多級頁面資料抓取思路

1】整體思路
    1.1> 爬取一級頁面,提取 所需資料+鏈接,繼續跟進
    1.2> 爬取二級頁面,提取 所需資料+鏈接,繼續跟進
    1.3> ... ...2】代碼實作思路
    2.1> 避免重復代碼 - 請求、決議需定義函式

UserAgent反爬處理

1】基于User-Agent反爬
	1.1) 發送請求攜帶請求頭: headers={'User-Agent' : 'Mozilla/5.0 xxxxxx'}
	1.2) 多個請求時隨機切換User-Agent
        a) 定義py檔案存放大量User-Agent,匯入后使用random.choice()每次隨機選擇
        b) 使用fake_useragent模塊每次訪問隨機生成User-Agent
           from fake_useragent import UserAgent
           agent = UserAgent().random
   細節要點:pycharm中下載fake-useragent
        
【2】回應內容存在特殊字符
	解碼時使用ignore引數
    html = requests.get(url=url, headers=headers).content.decode('', 'ignore')

Cookie反爬

Cookie引數使用

  1. cookies引數的形式:字典

    cookies = {"cookie的name":"cookie的value"}

    • 該字典對應請求頭中Cookie字串,以分號、空格分割每一對字典鍵值對
    • 等號左邊的是一個cookie的name,對應cookies字典的key
    • 等號右邊對應cookies字典的value
  2. cookies引數的使用方法

    response = requests.get(url, cookies)

  3. 將cookie字串轉換為cookies引數所需的字典:

    cookies_dict = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}

  4. 注意:cookie一般是有過期時間的,一旦過期需要重新獲取

CookieJar物件轉換為Cookies字典

使用requests獲取的resposne物件,具有cookies屬性,該屬性值是一個cookieJar型別,包含了對方服務器設定在本地的cookie,我們如何將其轉換為cookies字典呢?

  1. 轉換方法

    cookies_dict = requests.utils.dict_from_cookiejar(response.cookies)

  2. 其中response.cookies回傳的就是cookieJar型別的物件

  3. requests.utils.dict_from_cookiejar函式回傳cookies字典

requests模塊引數總結

【1】方法一 : requests.get()
【2】引數
   2.1) url
   2.2) headers
   2.3) timeout
   2.4) proxies

【3】方法二 :requests.post()
【4】引數
    data

requests.get()

  • 思路

    【1】url
    【2】proxies -> {}
         proxies = {
            'http':'http://1.1.1.1:8888',
    	    'https':'https://1.1.1.1:8888'
         }
    【3】timeout
    【4】headers
    【5】cookies
    

requests.post()

  • 適用場景

    1】適用場景 : Post型別請求的網站
    
    【2】引數 : data={}
       2.1) Form表單資料: 字典
       2.2) res = requests.post(url=url,data=data,headers=headers)3】POST請求特點 : Form表單提交資料
        
        data : 字典,Form表單資料
    
  • pycharm中正則處理headers和formdata

    1】pycharm進入方法 :Ctrl + r ,選中 Regex
    【2】處理headers和formdata
        (.*): (.*)
        "$1": "$2",3】點擊 Replace All
    
  • 經典Demo有道翻譯

request.session()

  • requests模塊中的Session類能夠自動處理發送請求獲取回應程序中產生的cookie,進而達到狀態保持的目的,接下來我們就來學習它

作用與應用場景

  • requests.session的作用
    • 自動處理cookie,即 下一次請求會帶上前一次的cookie
  • requests.session的應用場景
    • 自動處理連續的多次請求程序中產生的cookie

使用方法

session實體在請求了一個網站后,對方服務器設定在本地的cookie會保存在session中,下一次再使用session請求對方服務器的時候,會帶上前一次的cookie

session = requests.session() # 實體化session物件
response = session.get(url, headers, ...)
response = session.post(url, data, ...)
  • session物件發送get或post請求的引數,與requests模塊發送請求的引數完全一致

response

response.text 和response.content的區別:

  • response.text
    • 型別:str
    • 解碼型別: requests模塊自動根據HTTP 頭部對回應的編碼作出有根據的推測,推測的文本編碼
  • response.content
    • 型別:bytes
    • 解碼型別: 沒有指定

動態加載資料抓取-Ajax

  • 特點

    1】右鍵 -> 查看網頁原始碼中沒有具體資料
    【2】滾動滑鼠滑輪或其他動作時加載,或者頁面區域重繪
    
  • 抓取

    1】F12打開控制臺,頁面動作抓取網路資料包
    【2】抓取json檔案URL地址
       2.1) 控制臺中 XHR :異步加載的資料包
       2.2) XHR -> QueryStringParameters(查詢引數)
    
  • 經典Demo:豆瓣電影

json決議模塊

json.loads(json)

1】作用 : 把json格式的字串轉為Python資料型別

【2】示例 : html = json.loads(res.text)

json.dump(python,f,ensure_ascii=False)

1】作用
   把python資料型別 轉為 json格式的字串,一般讓你把抓取的資料保存為json檔案時使用

【2】引數說明
   2.1)1個引數: python型別的資料(字典,串列等)
   2.2)2個引數: 檔案物件
   2.3)3個引數: ensure_ascii=False 序列化時編碼
  
【3】示例代碼
    # 示例1
    import json

    item = {'name':'QQ','app_id':1}
    with open('小米.json','a') as f:
      json.dump(item,f,ensure_ascii=False)
  
    # 示例2
    import json

    item_list = []
    for i in range(3):
      item = {'name':'QQ','id':i}
      item_list.append(item)

    with open('xiaomi.json','a') as f:
        json.dump(item_list,f,ensure_ascii=False)

jsonpath

jsonpath使用示例

book_dict = { 
  "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

from jsonpath import jsonpath

print(jsonpath(book_dict, '$..author')) # 如果取不到將回傳False # 回傳串列,如果取不到將回傳False

在這里插入圖片描述

json模塊總結

# 爬蟲最常用1】資料抓取 - json.loads(html)
    將回應內容由: json 轉為 python
【2】資料保存 - json.dump(item_list,f,ensure_ascii=False)
    將抓取的資料保存到本地 json檔案

# 抓取資料一般處理方式1】txt檔案
【2】csv檔案
【3】json檔案
【4】MySQL資料庫
【5】MongoDB資料庫
【6】Redis資料庫

控制臺抓包

  • 打開方式及常用選項

    1】打開瀏覽器,F12打開控制臺,找到Network選項卡
    
    【2】控制臺常用選項
       2.1) Network: 抓取網路資料包
         a> ALL: 抓取所有的網路資料包
         b> XHR:抓取異步加載的網路資料包
         c> JS : 抓取所有的JS檔案
       2.2) Sources: 格式化輸出并打斷點除錯JavaScript代碼,助于分析爬蟲中一些引數
       2.3) Console: 互動模式,可對JavaScript中的代碼進行測驗
        
    【3】抓取具體網路資料包后
       3.1) 單擊左側網路資料包地址,進入資料包詳情,查看右側
       3.2) 右側:
         a> Headers: 整個請求資訊
            General、Response Headers、Request Headers、Query String、Form Data
         b> Preview: 對回應內容進行預覽
         c> Response:回應內容
    

代理設定

定義及分類

代理ip的匿名程度,代理IP可以分為下面三類:
    1.透明代理(Transparent Proxy):透明代理雖然可以直接“隱藏”你的IP地址,但是還是可以查到你是誰,
    2.匿名代理(Anonymous Proxy):使用匿名代理,別人只能知道你用了代理,無法知道你是誰,
    3.高匿代理(Elite proxy或High Anonymity Proxy):高匿代理讓別人根本無法發現你是在用代理,所以是最好的選擇,
    
代理服務請求使用的協議可以分為:
	1.http代理:目標url為http協議
	2.https代理:目標url為https協議
	3.socks隧道代理(例如socks5代理)等:
      socks 代理只是簡單地傳遞資料包,不關心是何種應用協議(FTP、HTTP和HTTPS等),
      socks 代理比http、https代理耗時少,
      socks 代理可以轉發http和https的請求

普通代理思路

1】獲取代理IP網站
   西刺代理、快代理、全網代理、代理精靈、阿布云、芝麻代理... ...2】引數型別
   proxies = { '協議':'協議://IP:埠號' }
   proxies = {
    	'http':'http://IP:埠號',
    	'https':'https://IP:埠號',
   }

普通代理

# 使用免費普通代理IP訪問測驗網站: http://httpbin.org/get
import requests

url = 'http://httpbin.org/get'
headers = {'User-Agent':'Mozilla/5.0'}
# 定義代理,在代理IP網站中查找免費代理IP
proxies = {
    'http':'http://112.85.164.220:9999',
    'https':'https://112.85.164.220:9999'
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)

私密代理+獨享代理

1】語法結構
   proxies = { '協議':'協議://用戶名:密碼@IP:埠號' }2】示例
   proxies = {
	  'http':'http://用戶名:密碼@IP:埠號',
      'https':'https://用戶名:密碼@IP:埠號',
   }

私密代理+獨享代理 - 示例代碼

import requests
url = 'http://httpbin.org/get'
proxies = {
    'http': 'http://309435365:szayclhp@106.75.71.140:16816',
    'https':'https://309435365:szayclhp@106.75.71.140:16816',
}
headers = {
    'User-Agent' : 'Mozilla/5.0',
}

html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)

建立自己的代理IP池 - 開放代理 | 私密代理

"""
收費代理:
    建立開放代理的代理IP池
思路:
    1、獲取到開放代理
    2、依次對每個代理IP進行測驗,能用的保存到檔案中
"""
import requests

class ProxyPool:
    def __init__(self):
        self.url = '代理網站的API鏈接'
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36'}
        # 打開檔案,用來存放可用的代理IP
        self.f = open('proxy.txt', 'w')

    def get_html(self):
        html = requests.get(url=self.url, headers=self.headers).text
        proxy_list = html.split('\r\n')
        for proxy in proxy_list:
            # 依次測驗每個代理IP是否可用
            if self.check_proxy(proxy):
                self.f.write(proxy + '\n')

    def check_proxy(self, proxy):
        """測驗1個代理IP是否可用,可用回傳True,否則回傳False"""
        test_url = 'http://httpbin.org/get'
        proxies = {
            'http' : 'http://{}'.format(proxy),
            'https': 'https://{}'.format(proxy)
        }
        try:
            res = requests.get(url=test_url, proxies=proxies, headers=self.headers, timeout=2)
            if res.status_code == 200:
                print(proxy,'\033[31m可用\033[0m')
                return True
            else:
                print(proxy,'無效')
                return False
        except:
            print(proxy,'無效')
            return False

    def run(self):
        self.get_html()
        # 關閉檔案
        self.f.close()

if __name__ == '__main__':
    spider = ProxyPool()
    spider.run()

拉勾網阿布云代理

import json
import re
import time
import requests
import multiprocessing
from job_data_analysis.lagou_spider.handle_insert_data import lagou_mysql


class HandleLaGou(object):
    def __init__(self):
        #使用session保存cookies資訊
        self.lagou_session = requests.session()
        self.header = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
        }
        self.city_list = ""

    #獲取全國所有城市串列的方法
    def handle_city(self):
        city_search = re.compile(r'www\.lagou\.com\/.*\/">(.*?)</a>')
        city_url = "https://www.lagou.com/jobs/allCity.html"
        city_result = self.handle_request(method="GET",url=city_url)
        #使用正則運算式獲取城市串列
        self.city_list = set(city_search.findall(city_result))
        self.lagou_session.cookies.clear()

    def handle_city_job(self,city):
        first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%city
        first_response = self.handle_request(method="GET",url=first_request_url)
        total_page_search = re.compile(r'class="span\stotalNum">(\d+)</span>')
        try:
            total_page = total_page_search.search(first_response).group(1)
            print(city,total_page)
        #由于沒有崗位資訊造成的exception
        except:
            return
        else:
            for i in range(1,int(total_page)+1):
                data = {
                    "pn":i,
                    "kd":"web"
                }
                page_url = "https://www.lagou.com/jobs/positionAjax.json?city=%s&needAddtionalResult=false"%city
                referer_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%city
                #referer的URL需要進行encode
                self.header['Referer'] = referer_url.encode()
                response = self.handle_request(method="POST",url=page_url,data=data,info=city)
                lagou_data = json.loads(response)
                job_list = lagou_data['content']['positionResult']['result']
                for job in job_list:
                    lagou_mysql.insert_item(job)



    def handle_request(self,method,url,data=None,info=None):
        while True:
            #加入阿布云的動態代理
            proxyinfo = "http://%s:%s@%s:%s" % ('賬號', '密碼', 'http-dyn.abuyun.com', '9020')
            proxy = {
                "http":proxyinfo,
                "https":proxyinfo
            }
            try:
                if method == "GET":
                    response = self.lagou_session.get(url=url,headers=self.header,proxies=proxy,timeout=6)
                elif method == "POST":
                    response = self.lagou_session.post(url=url,headers=self.header,data=data,proxies=proxy,timeout=6)
            except:
                # 需要先清除cookies資訊
                self.lagou_session.cookies.clear()
                # 重新獲取cookies資訊
                first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput=" % info
                self.handle_request(method="GET", url=first_request_url)
                time.sleep(10)
                continue
            response.encoding = 'utf-8'
            if '頻繁' in response.text:
                print(response.text)
                #需要先清除cookies資訊
                self.lagou_session.cookies.clear()
                # 重新獲取cookies資訊
                first_request_url = "https://www.lagou.com/jobs/list_python?city=%s&cl=false&fromSearch=true&labelWords=&suginput="%info
                self.handle_request(method="GET",url=first_request_url)
                time.sleep(10)
                continue
            return response.text

if __name__ == '__main__':
    lagou = HandleLaGou()
    #所有城市的方法
    lagou.handle_city()
    print(lagou.city_list)
    #引入多行程加速抓取
    pool = multiprocessing.Pool(2)
    for city in lagou.city_list:
        pool.apply_async(lagou.handle_city_job,args=(city,))
    pool.close()
    pool.join()

unicode與encode

  • unicode: 作用是將unicode編碼轉換成其他編碼的字串,將所有語言統一到unicode中 [如果內容是英文,unicode編碼比ASCII多一倍的存盤空間,同時傳輸需要多一倍的傳輸]

  • encode : 作用是將unicode編碼轉換成其他編碼的字串

  • decode:作用是將其他編碼的字串轉換成unicode編碼,需要指明原來的編碼格式

    • 編碼換:

      s = ("我愛中國,i love china")
      s.decode("gb2312").encode("utf-8")
      
    • 查看當前編碼

      import sys
      sys.getdefaultencoding()
      
  • python3中用unicode進行編碼,因此能直接用用unicode來編碼:s.encode(“utf-8”)

  • 通常情況下window是GB2312編碼

  • linux通常情況下是utf8的編碼

決議模塊總結

re正則決議

import re 
pattern = re.compile('正則運算式',re.S)
r_list = pattern.findall(html)

在這里插入圖片描述

lxml+xpath決議

from lxml import etree
p = etree.HTML(res.text)
r_list = p.xpath('xpath運算式')

【謹記】只要呼叫了xpath,得到的結果一定為'串列'

xpath運算式

  • 匹配規則

    1】結果: 節點物件串列
       1.1) xpath示例: //div、//div[@class="student"]//div/a[@title="stu"]/span
    
    【2】結果: 字串串列
       2.1) xpath運算式中末尾為: @src、@href、/text()
    
  • 最常用

    1】基準xpath運算式: 得到節點物件串列
    【2for r in [節點物件串列]:
           username = r.xpath('./xxxxxx')
    
    【注意】遍歷后繼續xpath一定要以:  . 開頭,代表當前節點
    
  • 豆瓣書籍抓取

    import requests
    from lxml import etree
    from fake_useragent import UserAgent
    import time
    import random
    
    class DoubanBookSpider:
        def __init__(self):
            self.url = 'https://book.douban.com/top250?start={}'
    
        def get_html(self, url):
            """使用隨機的User-Agent"""
            headers = {'User-Agent':UserAgent().random}
            html = requests.get(url=url, headers=headers).text
            self.parse_html(html)
    
        def parse_html(self, html):
            """lxml+xpath進行資料決議"""
            parse_obj = etree.HTML(html)
            # 1.基準xpath:提取每本書的節點物件串列
            table_list = parse_obj.xpath('//div[@class="indent"]/table')
            for table in table_list:
                item = {}
                # 書名
                name_list = table.xpath('.//div[@class="pl2"]/a/@title')
                item['name'] = name_list[0].strip() if name_list else None
                # 描述
                content_list = table.xpath('.//p[@class="pl"]/text()')
                item['content'] = content_list[0].strip() if content_list else None
                # 評分
                score_list = table.xpath('.//span[@class="rating_nums"]/text()')
                item['score'] = score_list[0].strip() if score_list else None
                # 評價人數
                nums_list = table.xpath('.//span[@class="pl"]/text()')
                item['nums'] = nums_list[0][1:-1].strip() if nums_list else None
                # 類別
                type_list = table.xpath('.//span[@class="inq"]/text()')
                item['type'] = type_list[0].strip() if type_list else None
    
                print(item)
    
        def run(self):
            for i in range(5):
                start = (i - 1) * 25
                page_url = self.url.format(start)
                self.get_html(page_url)
                time.sleep(random.randint(1,2))
    
    if __name__ == '__main__':
        spider = DoubanBookSpider()
        spider.run()
    

資料持久化

mysql

"""
sql 表創建

mysql -uroot -p
create database maoyandb charset utf8;
use maoyandb;
create table maoyantab(
name varchar(100),
star varchar(300),
time varchar(100)
)charset=utf8;
"""
"""
    pymysql模塊使用
"""
import pymysql

# 1.連接資料庫
db = pymysql.connect(
    'localhost','root','123456','maoyandb',charset='utf8'
)
cur = db.cursor()
# 2.執行sql命令
ins = 'insert into maoyantab values(%s,%s,%s)'
cur.execute(ins, ['肖申克的救贖','主演:張國榮,張曼玉,劉德華','2018-06-25'])
# 3.提交到資料庫執行
db.commit()

cur.close()
db.close()

Mysql模板

import pymysql

# __init__(self):
	self.db = pymysql.connect('IP',... ...)
	self.cursor = self.db.cursor()
	
# save_html(self,r_list):
	self.cursor.execute('sql',[data1])
    self.cursor.executemany('sql', [(),(),()])
	self.db.commit()
	
# run(self):
	self.cursor.close()
	self.db.close()

mongodb

  • https://www.runoob.com/python3/python-mongodb.html 【菜鳥教程】
"""
【1】非關系型資料庫,資料以鍵值對方式存盤,埠27017
【2】MongoDB基于磁盤存盤
【3】MongoDB資料型別單一,值為JSON檔案,而Redis基于記憶體,
   3.1> MySQL資料型別:數值型別、字符型別、日期時間型別、列舉型別
   3.2> Redis資料型別:字串、串列、哈希、集合、有序集合
   3.3> MongoDB資料型別:值為JSON檔案
【4】MongoDB: 庫 -> 集合 -> 檔案
     MySQL  : 庫 -> 表  ->  表記錄
"""

"""
Linux進入: mongo
>show dbs                  - 查看所有庫
>use 庫名                   - 切換庫
>show collections          - 查看當前庫中所有集合
>db.集合名.find().pretty()  - 查看集合中檔案
>db.集合名.count()          - 統計檔案條數
>db.集合名.drop()           - 洗掉集合
>db.dropDatabase()         - 洗掉當前庫
"""
import pymongo

# 創建連接物件
connect = pymongo.MongoClient(host='127.0.0.1',port=27017)
# 連接庫物件
db = connect['maoyandb']
# 創建集合物件
myset = db['maoyanset']
# 插入單條資料
# myset.insert_one({'name':'錢天一'})
# 插入多條資料
myset.insert_many[{'name':'張三'},{'name':'李四'},{'name':'王五'}]

mongodb模板

import requests
import re
import time
import random
import pymongo

class MaoyanSpider:
    def __init__(self):
        self.url = 'https://maoyan.com/board/4?offset={}'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'}
        # 三個物件:連接物件、庫物件、庫集合
        self.conn = pymongo.MongoClient('127.0.0.1',27017)
        self.db = self.conn['maoyandb']
        self.myset = self.db['maoyanset']

    ##提取網頁資料
    def get_html(self,url):
        html = requests.get(url,url,headers=self.headers).text
        self.parse_html(html)

    ##決議網頁資料
    def parse_html(self,html):
        regex =  '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>'
        pattern = re.compile(regex,re.S)
        r_list = pattern.findall(html)
        self.save_html(r_list)

    ## 資料處理提取
    def save_html(self,r_list):
        for r in r_list:
            item ={}
            item['name'] = r[0].strip()
            item['star'] = r[1].strip()
            item['time'] = r[2].strip()
            print(item)
            # 存入到mongodb資料庫
            self.myset.insert_one(item)

    def run(self):
        """程式入口函式"""
        for offset in range(0, 91, 10):
            url = self.url.format(offset)
            self.get_html(url=url)
            # 控制資料抓取頻率:uniform()生成指定范圍內的浮點數
            time.sleep(random.uniform(0, 1))

if __name__ == '__main__':
    spider = MaoyanSpider()
    spider.run()

Json

import json
# Demo1
item = {'name':'QQ','e-mail':99362}
with open('qq.json','a')as f:
    json.dump(item,f,ensure_ascii=False)


# Demo2
# import json
# item_list =[]
# for i in range(3):
#     item = {'name':'QQ','e-mail':'99362'}
#     item_list.append(item)
#
# with open('demo2.json','a')as f:
#     json.dump(item_list,f,ensure_ascii=False)

Json模板

import requests
from fake_useragent import UserAgent
import time
import random
import re
import json

# 豆瓣電影全堆疊抓取
class DoubanSpider:
    def __init__(self):
        self.url = 'https://movie.douban.com/j/chart/top_list?'
        self.i = 0
        # 存入json檔案
        self.f = open('douban.json', 'w', encoding='utf-8')
        self.all_film_list = []

    def get_agent(self):
        """獲取隨機的User-Agent"""
        return UserAgent().random

    def get_html(self, params):
        headers = {'User-Agent':self.get_agent()}
        html = requests.get(url=self.url, params=params, headers=headers).text
        # 把json格式的字串轉為python資料型別
        html = json.loads(html)

        self.parse_html(html)

    def parse_html(self, html):
        """決議"""
        # html: [{},{},{},{}]
        item = {}
        for one_film in html:
            item['rank'] = one_film['rank']
            item['title'] = one_film['title']
            item['score'] = one_film['score']
            print(item)
            self.all_film_list.append(item)
            self.i += 1

    def run(self):
        # d: {'劇情':'11','愛情':'13','喜劇':'5',...,...}
        d = self.get_d()
        # 1、給用戶提示,讓用戶選擇
        menu = ''
        for key in d:
            menu += key + '|'
        print(menu)
        choice = input('請輸入電影類別:')
        if choice in d:
            code = d[choice]
            # 2、total: 電影總數
            total = self.get_total(code)
            for start in range(0,total,20):
                params = {
                    'type': code,
                    'interval_id': '100:90',
                    'action': '',
                    'start': str(start),
                    'limit': '20'
                }
                self.get_html(params=params)
                time.sleep(random.randint(1,2))

            # 把資料存入json檔案
            json.dump(self.all_film_list, self.f, ensure_ascii=False)
            self.f.close()
            print('數量:',self.i)
        else:
            print('請做出正確的選擇')

    def get_d(self):
        """{'劇情':'11','愛情':'13','喜劇':'5',...,...}"""
        url = 'https://movie.douban.com/chart'
        html = requests.get(url=url,headers={'User-Agent':self.get_agent()}).text
        regex = '<span><a href=".*?type_name=(.*?)&type=(.*?)&interval_id=100:90&action=">'
        pattern = re.compile(regex, re.S)
        # r_list: [('劇情','11'),('喜劇','5'),('愛情':'13')... ...]
        r_list = pattern.findall(html)
        # d: {'劇情': '11', '愛情': '13', '喜劇': '5', ..., ...}
        d = {}
        for r in r_list:
            d[r[0]] = r[1]

        return d

    def get_total(self, code):
        """獲取某個類別下的電影總數"""
        url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(code)
        html = requests.get(url=url,headers={'User-Agent':self.get_agent()}).text
        html = json.loads(html)

        return html['total']

if __name__ == '__main__':
    spider = DoubanSpider()
    spider.run()

json常用操作

import json
 
data = {
    'name': 'pengjunlee',
    'age': 32,
    'vip': True,
    'address': {'province': 'GuangDong', 'city': 'ShenZhen'}
}
# 將 Python 字典型別轉換為 JSON 物件
json_str = json.dumps(data)
print(json_str) # 結果 {"name": "pengjunlee", "age": 32, "vip": true, "address": {"province": "GuangDong", "city": "ShenZhen"}}
 
# 將 JSON 物件型別轉換為 Python 字典
user_dic = json.loads(json_str)
print(user_dic['address']) # 結果 {'province': 'GuangDong', 'city': 'ShenZhen'}
 
# 將 Python 字典直接輸出到檔案
with open('pengjunlee.json', 'w', encoding='utf-8') as f:
    json.dump(user_dic, f, ensure_ascii=False, indent=4)
 
# 將類檔案物件中的JSON字串直接轉換成 Python 字典
with open('pengjunlee.json', 'r', encoding='utf-8') as f:
    ret_dic = json.load(f)
    print(type(ret_dic)) # 結果 <class 'dict'>
    print(ret_dic['name']) # 結果 pengjunlee

json存盤串列

import json

all_app_list = [
    {'name':'QQ'},
    {'name':'王者榮耀'},
    {'name':'和平精英'}
]

with open('xiaomi.json', 'w') as f:
    json.dump(all_app_list, f, ensure_ascii=False)

CSV模板

import csv
from urllib import request, parse
import re
import time
import random


class MaoyanSpider(object):
  def __init__(self):
    self.url = 'https://maoyan.com/board/4?offset={}'
    # 計數
    self.num = 0


  def get_html(self, url):
    headers = {
        'user-agent': 'Mozilla / 5.0(Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
    }
    req = request.Request(url=url, headers=headers)
    res = request.urlopen(req)
    html = res.read().decode('utf-8')
    # 直接呼叫決議函式
    self.parse_html(html)

  def parse_html(self, html):
    # 創建正則的編譯物件
    re_ = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p> '
    pattern = re.compile(re_, re.S)
    # film_list:[('霸王別姬','張國榮','1993')]
    film_list = pattern.findall(html)
    self.write_html(film_list)

  # 存入csv檔案-writerrows
  def write_html(self, film_list):
    L = []
    with open('maoyanfilm.csv', 'a',newline='') as f:
      # 初始化寫入物件,注意引數f不能忘
      writer = csv.writer(f)
      for film in film_list:
        t = (
          film[0].strip(),
          film[1].strip(),
          film[2].strip()[5:15]
        )
        self.num += 1
        L.append(t)
      # writerow()引數為串列
      writer.writerows(L)
      print(L)


  def main(self):
    for offset in range(0, 91, 10):
      url = self.url.format(offset)
      self.get_html(url)
      time.sleep(random.randint(1, 2))
    print('共抓取資料', self.num, "部")


if __name__ == '__main__':
  start = time.time()
  spider = MaoyanSpider()
  spider.main()
  end = time.time()
  print('執行時間:%.2f' % (end - start))

txt模板

注意: 如果需要換行要自己在寫入內容中添加\n

  • 單行寫入
# 以二進制方式寫入
f  = open("write.txt","wb")
# 以二進制方式追加
# f  = open("write.txt","ab")
# 寫入
res = f.write(b"Big Bang Bang\n")
print(res)
res = f.write(b"Big Bang Bang\n")
print(res)
#關閉
f.close()
  • 多行寫入
f  = open("write.txt","w")
# 寫入資訊
msg =  f.writelines(["你好","我很好","那就好"])
# 關閉
f.close()

redis增量URl爬蟲實作思路

在這里插入圖片描述

1】原理
    利用Redis集合特性,可將抓取過的指紋添加到redis集合中,根據回傳值來判定是否需要抓取
	回傳值為1 : 代表之前未抓取過,需要進行抓取
	回傳值為0 : 代表已經抓取過,無須再次抓取
    
    hash加密:md5 32位、sha1 40位
    
    創建md5物件
    用update將href轉為byte型別
    最后通過hexdigest獲取加密碼
    
【2】代碼實作模板
import redis
from hashlib import md5
import sys

class XxxIncrSpider:
  def __init__(self):
    self.r = redis.Redis(host='localhost',port=6379,db=0)
    
  def url_md5(self,url):
    """對URL進行md5加密函式"""
    s = md5()
    s.update(url.encode())
    return s.hexdigest()
  
  def run_spider(self):
    href_list = ['url1','url2','url3','url4']
    for href in href_list:
      href_md5 = self.url_md5(href)
      if self.r.sadd('spider:urls',href_md5) == 1:
        回傳值為1表示添加成功,即之前未抓取過,則開始抓取
      else:
        sys.exit()

休眠設定

# 控制資料抓取頻率:uniform()生成制定范圍內的浮點數
time.sleep(random.uniform(2,5))
# 生成整形的陣列
time.sleep(random.randint(1,2))

時間引數

import datetime
timestape = str(datetime.datetime.now()).split(".")[0]

打碼平臺

  • 圖鑒
  • 超級鷹

云詞

import os,time,json,random,jieba,requests
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from wordcloud import WordCloud

# 詞云形狀圖片
WC_MASK_IMG = 'wawa.jpg'
# 評論資料保存檔案
COMMENT_FILE_PATH = 'jd_comment.txt'
# 詞云字體
WC_FONT_PATH = '/Library/Fonts/Songti.ttc'

def spider_comment(page=0):
    """
    爬取京東指定頁的評價資料
    :param page: 爬取第幾,默認值為0
    """
    url = 'https://sclub.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv4646&productId=1263013576&score=0&sortType=5&page=%s&pageSize=10&isShadowSku=0&fold=1' % page
    kv = {'user-agent': 'Mozilla/5.0', 'Referer': 'https://item.jd.com/1263013576.html'}
    # proxies = {
    #     '1.85.5.66':'8060',
    #     '171.11.178.223':'9999',
    #     '120.194.42.157':'38185',
    #     '161.35.4.201':'80',
    #     '175.42.123.196':'9999',
    # }
    try:
        r = requests.get(url, headers=kv)#,proxies=proxies
        r.raise_for_status()
    except:
        print('爬取失敗')
    # 截取json資料字串
    r_json_str = r.text[26:-2]
    # 字串轉json物件
    r_json_obj = json.loads(r_json_str)
    # 獲取評價串列資料
    r_json_comments = r_json_obj['comments']
    # 遍歷評論物件串列
    for r_json_comment in r_json_comments:
        # 以追加模式換行寫入每條評價
        with open(COMMENT_FILE_PATH, 'a+') as file:
            file.write(r_json_comment['content'] + '\n')
        # 列印評論物件中的評論內容
        print(r_json_comment['content'])

def batch_spider_comment():
    """
    批量爬取某東評價
    """
    # 寫入資料前先清空之前的資料
    if os.path.exists(COMMENT_FILE_PATH):
        os.remove(COMMENT_FILE_PATH)
    for i in range(3):
        spider_comment(i)
        # 模擬用戶瀏覽,設定一個爬蟲間隔,防止ip被封
        time.sleep(random.random() * 5)

def cut_word():
    """
    對資料分詞
    :return: 分詞后的資料
    """
    with open(COMMENT_FILE_PATH) as file:
        comment_txt = file.read()
        wordlist = jieba.cut(comment_txt, cut_all=True)
        wl = " ".join(wordlist)
        print(wl)
        return wl

def create_word_cloud():
    """
    生成詞云
    :return:
    """
    # 設定詞云形狀圖片
    wc_mask = np.array(Image.open(WC_MASK_IMG))
    # 設定詞云的一些配置,如:字體,背景色,詞云形狀,大小
    wc = WordCloud(background_color="white", max_words=2000, mask=wc_mask, scale=4,
                   max_font_size=50, random_state=42, font_path=WC_FONT_PATH)
    # 生成詞云
    wc.generate(cut_word())

    # 在只設定mask的情況下,你將會得到一個擁有圖片形狀的詞云
    plt.imshow(wc, interpolation="bilinear")
    plt.axis("off")
    plt.figure()
    plt.show()

if __name__ == '__main__':
    # 爬取資料
    batch_spider_comment()

    # 生成詞云
    create_word_cloud()

多執行緒爬蟲

應用場景

1】多行程 :CPU密集程式
【2】多執行緒 :爬蟲(網路I/O)、本地磁盤I/O

多執行緒爬蟲示例【豆瓣】

# 抓取豆瓣電影劇情類別下的電影資訊
"""
豆瓣電影 - 劇情 - 抓取
"""
import requests
from fake_useragent import UserAgent
import time
import random
from threading import Thread,Lock
from queue import Queue

class DoubanSpider:
    def __init__(self):
        self.url = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start={}&limit=20'
        self.i = 0
        # 佇列 + 鎖
        self.q = Queue()
        self.lock = Lock()

    def get_agent(self):
        """獲取隨機的User-Agent"""
        return UserAgent().random

    def url_in(self):
        """把所有要抓取的URL地址入佇列"""
        for start in range(0,684,20):
            url = self.url.format(start)
            # url入佇列
            self.q.put(url)

    # 執行緒事件函式:請求+決議+資料處理
    def get_html(self):
        while True:
            # 從佇列中獲取URL地址
            # 一定要在判斷佇列是否為空 和 get() 地址 前后加鎖,防止佇列中只剩一個地址時出現重復判斷
            self.lock.acquire()
            if not self.q.empty():
                headers = {'User-Agent': self.get_agent()}
                url = self.q.get()
                self.lock.release()

                html = requests.get(url=url, headers=headers).json()
                self.parse_html(html)
            else:
                # 如果佇列為空,則最終必須釋放鎖
                self.lock.release()
                break

    def parse_html(self, html):
        """決議"""
        # html: [{},{},{},{}]
        item = {}
        for one_film in html:
            item['rank'] = one_film['rank']
            item['title'] = one_film['title']
            item['score'] = one_film['score']
            print(item)
            # 加鎖 + 釋放鎖
            self.lock.acquire()
            self.i += 1
            self.lock.release()

    def run(self):
        # 先讓URL地址入佇列
        self.url_in()
        # 創建多個執行緒,開干吧
        t_list = []
        for i in range(1):
            t = Thread(target=self.get_html)
            t_list.append(t)
            t.start()

        for t in t_list:
            t.join()

        print('數量:',self.i)

if __name__ == '__main__':
    start_time = time.time()
    spider = DoubanSpider()
    spider.run()
    end_time = time.time()
    print('執行時間:%.2f' % (end_time-start_time))

selenium+PhantomJS/Chrome/Firefox

selenium

1】定義
    1.1) 開源的Web自動化測驗工具
    
【2】用途
    2.1) 對Web系統進行功能性測驗,版本迭代時避免重復勞動
    2.2) 兼容性測驗(測驗web程式在不同作業系統和不同瀏覽器中是否運行正常)
    2.3) 對web系統進行大數量測驗
    
【3】特點
    3.1) 可根據指令操控瀏覽器
    3.2) 只是工具,必須與第三方瀏覽器結合使用
    
【4】安裝
    4.1) Linux: sudo pip3 install selenium
    4.2) Windows: python -m pip install selenium

繞過selenium檢測

from selenium import webdriver
options = webdriver.ChromeOptions()
# 此步驟很重要,設定為開發者模式,防止被各大網站識別出來使用了Selenium
options.add_experimental_option('excludeSwitches', ['enable-automation'])
#停止加載圖片
options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
browser = webdriver.Chrome(options=options)
browser.get('https://www.taobao.com/')

selenium對cookie的處理

selenium能夠幫助我們處理頁面中的cookie,比如獲取、洗掉,接下來我們就學習這部分知識

獲取cookie

driver.get_cookies()回傳串列,其中包含的是完整的cookie資訊!不光有name、value,還有domain等cookie其他維度的資訊,所以如果想要把獲取的cookie資訊和requests模塊配合使用的話,需要轉換為name、value作為鍵值對的cookie字典

# 獲取當前標簽頁的全部cookie資訊
print(driver.get_cookies())
# 把cookie轉化為字典
cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()}

洗掉cookie

#洗掉一條cookie
driver.delete_cookie("CookieName")

# 洗掉所有的cookie
driver.delete_all_cookies()

selenium使用代理ip

selenium控制瀏覽器也是可以使用代理ip的!

  • 使用代理ip的方法

    • 實體化配置物件
      • options = webdriver.ChromeOptions()
    • 配置物件添加使用代理ip的命令
      • options.add_argument('--proxy-server=http://202.20.16.82:9527')
    • 實體化帶有配置物件的driver物件
      • driver = webdriver.Chrome('./chromedriver', chrome_options=options)
  • 參考代碼如下:

    from selenium import webdriver
    
    options = webdriver.ChromeOptions() # 創建一個配置物件
    options.add_argument('--proxy-server=http://202.20.16.82:9527') # 使用代理ip
    
    driver = webdriver.Chrome(chrome_options=options) # 實體化帶有配置的driver物件
    
    driver.get('http://www.itcast.cn')
    print(driver.title)
    driver.quit()
    

selenium替換user-agent

selenium控制谷歌瀏覽器時,User-Agent默認是谷歌瀏覽器的,這一小節我們就來學習使用不同的User-Agent

  • 替換user-agent的方法

    • 實體化配置物件
      • options = webdriver.ChromeOptions()
    • 配置物件添加替換UA的命令
      • options.add_argument('--user-agent=Mozilla/5.0 HAHA')
    • 實體化帶有配置物件的driver物件
      • driver = webdriver.Chrome('./chromedriver', chrome_options=options)
  • 參考代碼如下:

    from selenium import webdriver
    
    options = webdriver.ChromeOptions() # 創建一個配置物件
    options.add_argument('--user-agent=Mozilla/5.0 HAHA') # 替換User-Agent
    
    driver = webdriver.Chrome('./chromedriver', chrome_options=options)
    
    driver.get('http://www.itcast.cn')
    print(driver.title)
    driver.quit()
    

  • selenium替換user-agent

指定埠遙控

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('debuggerAddress','127.0.0.1:9222')
browser=webdriver.Chrome(executable_path=r'C:\Users\TR\AppData\Local\Google\Chrome
\Application\chromedriver.exe',chrome_options=chrome_options)
browser.get('http://www.zhihu.com')

PhantomJS瀏覽器

1】定義
    phantomjs為無界面瀏覽器(又稱無頭瀏覽器),在記憶體中進行頁面加載,高效
 
【2】下載地址
    2.1) chromedriver : 下載對應版本
       http://npm.taobao.org/mirrors/chromedriver/
    
    2.2) geckodriver
       https://github.com/mozilla/geckodriver/releases
            
    2.3) phantomjs
       https://phantomjs.org/download.html

【3】Ubuntu安裝
    3.1) 下載后解壓 : tar -zxvf geckodriver.tar.gz 
        
    3.2) 拷貝解壓后檔案到 /usr/bin/ (添加環境變數)
         sudo cp geckodriver /usr/bin/
        
    3.3) 添加可執行權限
         sudo chmod 777 /usr/bin/geckodriver

【4】Windows安裝
    4.1) 下載對應版本的phantomjs、chromedriver、geckodriver
    4.2) 把chromedriver.exe拷貝到python安裝目錄的Scripts目錄下(添加到系統環境變數)
         # 查看python安裝路徑: where python
    4.3) 驗證
         cmd命令列: chromedriver
 
***************************總結**************************************1】解壓 - 放到用戶主目錄(chromedriver、geckodriver、phantomjs)2】拷貝 - sudo cp /home/tarena/chromedriver /usr/bin/3】權限 - sudo chmod 777 /usr/bin/chromedriver

# 驗證
【Ubuntu | Windows】
ipython3
from selenium import webdriver
webdriver.Chrome()
或者
webdriver.Firefox()

【mac】
ipython3
from selenium import webdriver
webdriver.Chrome(executable_path='/Users/xxx/chromedriver')
或者
webdriver.Firefox(executable_path='/User/xxx/geckodriver')

百度示例代碼

"""示例代碼一:使用 selenium+瀏覽器 打開百度"""

# 匯入seleinum的webdriver介面
from selenium import webdriver
import time

# 創建瀏覽器物件
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
# 5秒鐘后關閉瀏覽器
time.sleep(5)
browser.quit()
"""示例代碼二:打開百度,搜索趙麗穎,點擊搜索,查看"""

from selenium import webdriver
import time

# 1.創建瀏覽器物件 - 已經打開了瀏覽器
browser = webdriver.Chrome()
# 2.輸入: http://www.baidu.com/
browser.get('http://www.baidu.com/')
# 3.找到搜索框,向這個節點發送文字: 趙麗穎
browser.find_element_by_xpath('//*[@id="kw"]').send_keys('趙麗穎')
# 4.找到 百度一下 按鈕,點擊一下
browser.find_element_by_xpath('//*[@id="su"]').click()

瀏覽器物件(browser)方法

1】browser.get(url=url)   - 地址欄輸入url地址并確認   
【2】browser.quit()         - 關閉瀏覽器
【3】browser.close()        - 關閉當前頁
【4】browser.page_source    - HTML結構原始碼
【5】browser.page_source.find('字串')
    從html原始碼中搜索指定字串,沒有找到回傳:-1,經常用于判斷是否為最后一頁
【6】browser.maximize_window() - 瀏覽器視窗最大化

Selenium 定位節點八種方法

1】單元素查找('結果為1個節點物件')
    1.1) 【最常用】browser.find_element_by_id('id屬性值')
    1.2) 【最常用】browser.find_element_by_name('name屬性值')
    1.3) 【最常用】browser.find_element_by_class_name('class屬性值')
    1.4) 【最萬能】browser.find_element_by_xpath('xpath運算式')
    1.5) 【匹配a節點時常用】browser.find_element_by_link_text('鏈接文本')
    1.6) 【匹配a節點時常用】browser.find_element_by_partical_link_text('部分鏈接文本')
    1.7) 【最沒用】browser.find_element_by_tag_name('標記名稱')
    1.8) 【較常用】browser.find_element_by_css_selector('css運算式')2】多元素查找('結果為[節點物件串列]')
    2.1) browser.find_elements_by_id('id屬性值')
    2.2) browser.find_elements_by_name('name屬性值')
    2.3) browser.find_elements_by_class_name('class屬性值')
    2.4) browser.find_elements_by_xpath('xpath運算式')
    2.5) browser.find_elements_by_link_text('鏈接文本')
    2.6) browser.find_elements_by_partical_link_text('部分鏈接文本')
    2.7) browser.find_elements_by_tag_name('標記名稱')
    2.8) browser.find_elements_by_css_selector('css運算式')

貓眼電影示例

from selenium import webdriver
import time

url = 'https://maoyan.com/board/4'
browser = webdriver.Chrome()
browser.get(url)

def get_data():
    # 基準xpath: [<selenium xxx li at xxx>,<selenium xxx li at>]
    li_list = browser.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd')
    for li in li_list:
        item = {}
        # info_list: ['1', '霸王別姬', '主演:張國榮', '上映時間:1993-01-01', '9.5']
        info_list = li.text.split('\n')
        item['number'] = info_list[0]
        item['name'] = info_list[1]
        item['star'] = info_list[2]
        item['time'] = info_list[3]
        item['score'] = info_list[4]

        print(item)

while True:
    get_data()
    try:
        browser.find_element_by_link_text('下一頁').click()
        time.sleep(2)
    except Exception as e:
        print('恭喜你!抓取結束')
        browser.quit()
        break
  • 節點物件操作

    1】文本框操作
        1.1) node.send_keys('')  - 向文本框發送內容
        1.2) node.clear()        - 清空文本
        1.3) node.get_attribute('value') - 獲取文本內容
        
    【2】按鈕操作
        1.1) node.click()      - 點擊
        1.2) node.is_enabled() - 判斷按鈕是否可用
        1.3) node.get_attribute('value') - 獲取按鈕文本
    

chromedriver設定無界面模式

from selenium import webdriver

options = webdriver.ChromeOptions()
# 添加無界面引數
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)

selenium - 滑鼠操作

from selenium import webdriver
# 匯入滑鼠事件類
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')

# 移動到 設定,perform()是真正執行操作,必須有
element = driver.find_element_by_xpath('//*[@id="u1"]/a[8]')
ActionChains(driver).move_to_element(element).perform()

# 單擊,彈出的Ajax元素,根據鏈接節點的文本內容查找
driver.find_element_by_link_text('高級搜索').click()

selenium處理iframe反爬

  • 經典案例 民政局抓取、QQ郵箱登錄、163郵箱登錄
1】滑鼠操作
    from selenium.webdriver import ActionChains
    ActionChains(browser).move_to_element(node).perform()2】切換句柄
    all_handles = browser.window_handles
    time.sleep(1)
    browser.switch_to.window(all_handles[1])3】iframe子框架
    browser.switch_to.frame(iframe_element)
    # 寫法1 - 任何場景都可以: 
    iframe_node = browser.find_element_by_xpath('')
    browser.switch_to.frame(iframe_node)
    
    # 寫法2 - 默認支持 id 和 name 兩個屬性值:
    browser.switch_to.frame('id屬性值|name屬性值')

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/280698.html

標籤:python

上一篇:爬蟲實戰5:爬取全部穿越火線武器的圖片以武器名稱命名保存到本地檔案

下一篇:第一次Python接單的程序記錄

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more