《Python網絡爬蟲實戰》讀書筆記1

Python與網絡爬蟲

robots與Sitemap

robots文件指出該網站的信息爬取限制,在爬取的時候,檢查這一文件中的內容可以降低爬蟲程序被網站的反爬蟲機制封禁的風險。比如下面是百度的robots文件

在這裏插入圖片描述

該文件的內容介紹請參考:百度百科robots

Python3自帶的robotoparser工具可以解析該文件並指導自己的爬蟲,從未執行一些限制;比如下面的代碼,使用百度的user_agent,如果遵守robots協議,是不允許爬取taobao的;如果修改成自定義的user_agent則沒有這個限制

import urllib.robotparser as urobot
import requests

url = "https://www.taobao.com/"
rp = urobot.RobotFileParser()
rp.set_url(url + "/robots.txt")
rp.read()
# user_agent = 'Baiduspider' # cannot scrap because robots.txt banned you!
user_agent = 'Myspider' # seems good
if rp.can_fetch(user_agent, 'https://www.taobao.com/product/'):
    site = requests.get(url)
    print('seems good')
else:
    print("cannot scrap because robots.txt banned you!")

robots.txt有時候還會定義一個sitemap(站點地圖),在sitemap中會列出該網站的頁面,有助於訪問者以及搜索引擎的爬蟲找到網站中的各個頁面

查看網站所用的技術

在Python中可以使用wad模塊來檢測網站使用的技術類型

pip install wad
pip install six

可以使用如下代碼

import wad.detection
det = wad.detection.Detector()
url = "http://www.12306.cn"
json_data = det.detect(url)
print(json_data)

很方便的查看12306所用的技術,可惜我沒執行出來,還是老老實實的自己用chrome分析吧

在這裏插入圖片描述

數據採集

第一個完整的例子,試着爬取360新聞的數據,通過解析頁面的數據用bs拿到的數據如下:

  • 新聞的標題
  • 新聞的鏈接
  • 新聞的時間(要求轉換成具體的年月日)

在這裏插入圖片描述

本例子的核心亮點可能就只有這個時間轉換了,用的是arrow庫,一個比datetime更方便的高級API庫,單獨使用arrow庫的一個例子

#!/usr/bin/env python
# encoding: utf-8

import arrow

data_str_list = ["6天前", "2020-04-13"]

if __name__ == "__main__":
    for data_str in data_str_list:
        if len(data_str) < 6:
            output_date = arrow.now().replace(days=-int(data_str[:1])).date()
        else:
            output_date = arrow.get(data_str[:10], 'YYYY-MM-DD').date()
        print(output_date) # 2020-04-14 # 2020-04-13

因此使用到本例中,完整代碼如下

import requests
from bs4 import BeautifulSoup
import arrow

urls = [
	u'https://news.so.com/ns?q=北京&pn={}&tn=newstitle&rank=rank&j=0&nso=10&tp=11&nc=0&src=page'
		.format(i) for i in range(10)
]
for i, url in enumerate(urls):
	print(url, "=======")
	r = requests.get(url)
	bs1 = BeautifulSoup(r.text)
	items = bs1.find_all('a', class_='news_title')

	t_list = []
	for one in items:
		t_item = []
		if '360' in one.get('href'):
			continue
		t_item.append(one.get('href'))
		t_item.append(one.text)
		date = [one.next_sibling][0].find('span', class_='pdate').text

		if len(date) < 6:
			date = arrow.now().replace(days=-int(date[:1])).date()
		else:
			date = arrow.get(date[:10], 'YYYY-MM-DD').date()

		t_item.append(date)

		t_list.append(t_item)

	for one in t_list:
		print(one[1], one[0], one[2])

得到的每一個新聞項如下

在這裏插入圖片描述

文件與數據的存儲

CSV的讀寫

#!/usr/bin/env python
# encoding: utf-8

import csv

def write_to_csv():
    res_list = [['A', 'B', 'C'], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
    with open('output.csv', 'a', newline='') as f: # newline可以讓輸出不帶上換行
        writer = csv.writer(f, delimiter=',')
        writer.writerows(res_list)

def read_from_csv():
    with open('output.csv', 'r') as f:
        for line in f:
            print(line.split(','))

if __name__ == "__main__":
    write_to_csv()
    read_from_csv()

使用數據庫

目前比較常用的數據庫或許是MySQL了

使用MySQL

在Python中使用MySQL,最簡單的放肆可能是使用pymysql然後使用SQL語句進行操作了

建數據庫、建表語句如下

CREATE DATABASE test_python_mysql;

USE test_python_mysql;

DROP TABLE IF EXISTS test_python_mysql_table ;
CREATE TABLE `test_python_mysql_table` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `timestrap` VARCHAR(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

使用PyMySQL進行操作MySQL

import pymysql.cursors
# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='root',
                             password='123456',
                             db='test_python_mysql',
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)
try:
    with connection.cursor() as cursor:
        sql = "INSERT INTO `test_python_mysql_table` (`timestrap`) VALUES (%s)"
        cursor.execute(sql, ('123456789'))

    connection.commit()

    with connection.cursor() as cursor:
        sql = "SELECT `id`, `timestrap` FROM `test_python_mysql_table` WHERE `timestrap` = %s"
        cursor.execute(sql, ('123456789',))
        result = cursor.fetchone()
        print(result)
finally:
    connection.close()

輸出如下:

在這裏插入圖片描述

使用SQLite3

很多情況下,可能未必用得到MySQL這麼大型的數據庫,只需要保存在文件數據庫SQLite3即可

import sqlite3

database_name = 'new-sqlite3'
def create_table():
    conn = sqlite3.connect(database_name)
    print("Opened datavase successfully")
    cur = conn.cursor()
    cur.execute("""
    CREATE TABLE `test_python_mysql_table` (
      `id` integer NOT NULL PRIMARY KEY autoincrement,
      `timestrap` TEXT DEFAULT NULL
    );
    """)
    print("Table created successfully")
    conn.close()

def insert_table():
    conn = sqlite3.connect(database_name)
    c = conn.cursor()
    for i in range(3):
        timestrap = 123456781 + i
        insert_str = "INSERT INTO `test_python_mysql_table` (`timestrap`) VALUES ({0})".format(str(timestrap))
        c.execute(insert_str)
    conn.commit()
    print("Records created successfully")
    conn.close()

def select_from_table():
    conn = sqlite3.connect(database_name)
    c = conn.cursor()
    cursor = c.execute("SELECT * from test_python_mysql_table; ")
    for i in cursor.fetchall():
        print(i)

if __name__ == "__main__":
    create_table()
    insert_table()
    select_from_table()

使用SQLAlchemy

SQLAlchemy的出現,讓我們省略了自己手寫SQL語句的過程,類似在django裏面使用的數據插入一般,suiran SQLAlchemy是ORM工具,但也支持傳統的基於底層SQL語句的操作

使用進行SQLAlchemy建表以及增刪改查:

import pymysql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column, Integer, String, func
from sqlalchemy.orm import sessionmaker

pymysql.install_as_MySQLdb() # 如果沒有這個語句,在導入sqlalchemy時可能會報錯
Base = declarative_base()

class Test(Base):
    __tablename__ = "test_python_mysql_sqlalchemy"
    id = Column('id', Integer, primary_key=True, autoincrement=True)
    name = Column('name', String(50))
    age = Column('age', Integer)

engine = create_engine("mysql://root:123456@localhost:3306/test_python_mysql") # 如果沒有test_python_mysql數據庫需要先建

db_ses = sessionmaker(bind=engine)
session = db_ses()

Base.metadata.create_all(engine)

# 插入數據
user1 = Test(name='zeng1', age=26)
user2 = Test(name='zeng2', age=36)
user3 = Test(name='zeng3', age=46)
session.add(user1)
session.add(user2)
session.add(user3)

# 修改數據,使用merge()方法
user1.name = "zengraoli"
session.merge(user1)

users = session.query(Test)
print([(user.id, user.name, user.age) for user in users])

# 與上面等效的修改方式
session.query(Test).filter(Test.name=="zeng2").update({'name': "zengraoli2"})
# 刪除數據
session.query(Test).filter(Test.id==4).delete()
# 查詢數據
users = session.query(Test)
print([(user.id, user.name, user.age) for user in users])

# 按條件查詢
user = session.query(Test).filter(Test.age < 40).first() # 取出來第一個
print(user.name)

# 在結果中進行統計
user_count = session.query(Test.name).order_by(Test.name).count()
avg_age = session.query(func.avg(Test.age)).first()
sum_age = session.query(func.sum(Test.age)).first()
print(user_count, avg_age, sum_age)

session.close()

涉及到的建表語句,類似如下,如果以及存在該變,SQLAlchemy則會跳過建表過程

USE test_python_mysql;

DROP TABLE IF EXISTS test_python_mysql_sqlalchemy ;
CREATE TABLE `test_python_mysql_sqlalchemy` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(10) DEFAULT NULL,
  `age` INT(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

輸出結果如下

[(1, 'zengraoli', 26), (2, 'zeng2', 36), (3, 'zeng3', 46)]
[(1, 'zengraoli', 26), (2, 'zengraoli2', 36), (3, 'zeng3', 46)]
zengraoli
3 (Decimal('36.0000'),) (Decimal('108'),)

JavaScript與動態內容

使用Selenium

使用Selenium需要有對應的driver,可見參考鏈接:Windows下配置Chrome WebDriver

在這裏插入圖片描述

初步使用

開始嘗試使用Selenium打開百度新聞的頭條

from selenium import webdriver
import time

browser = webdriver.Chrome(r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe')
browser.get('http:www.baidu.com')
print(browser.title) # 輸出:"百度一下,你就知道"
browser.find_element_by_name("tj_trnews").click() # 點擊"新聞"
browser.find_element_by_class_name('hdline0').click() # 點擊頭條
print(browser.current_url) # 輸出:http://news.baidu.com/
time.sleep(10)
browser.quit() # 退出

觸發豆瓣的搜索

By是一個附加的用於網頁元素定位的元素,爲查找元素提供了更抽象的統一接口

from selenium import webdriver
import time
from selenium.webdriver.common.by import By

browser = webdriver.Chrome(r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe')
browser.get('http://www.douban.com')
time.sleep(1)
search_box = browser.find_element(By.NAME,'q')
search_box.send_keys('網站開發')
button = browser.find_element(By.CLASS_NAME,'bn') # 等價於browser.find_element_by_class_name(',bn')
button.click()

讓頁面進行滾動

send_keys(Keys.PAGE_DOWN)能夠模擬在瀏覽器中進行鼠標滾輪下滑的操作

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
import time

# 滾動頁面
browser = webdriver.Chrome(r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe')
browser.get('https://news.baidu.com/')
print(browser.title) # 輸出:"百度一下,你就知道"
for i in range(20):
  # browser.execute_script("window.scrollTo(0,document.body.scrollHeight)") # 使用執行JS的方式滾動
  ActionChains(browser).send_keys(Keys.PAGE_DOWN).perform() # 使用模擬鍵盤輸入的方式滾動
  time.sleep(0.5)

browser.quit() # 退出

拖拽元素到指定位置

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.alert import Alert

browser = webdriver.Chrome(r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe')
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
# 切換到一個frame
browser.switch_to.frame('iframeResult') #
# 不推薦browser.switch_to_frame()方法
# 根據id定位元素
source = browser.find_element_by_id('draggable') # 被拖拽區域
target = browser.find_element_by_id('droppable') # 目標區域
ActionChains(browser).drag_and_drop(source, target).perform() # 執行動作鏈
alt = Alert(browser)
print(alt.text) # 輸出:"dropped"
alt.accept() # 接受彈出框

PyV8與Splash

V8是一款基於C++編寫的JS引擎,是一個能夠用來執行JS的運行工具,只要配合網頁DOM樹解析,在理論上能夠當做一個瀏覽器來使用。首先需要安裝PyV8

根據該篇blog文:Windows Python 運行js模塊

並沒有使用書中提示的PyV8(我自己也試了一下,從github下載了那個PyV8.py文件的確比較麻煩),改用PyExecJs模塊

pip install PyExecJs

測試執行js代碼

import execjs

js_source = """
var hi =(function(){
        function hi(){
            return "Hi!";
        }
        return hi();
    })
"""
#通過compile命令轉成一個js對象
docjs = execjs.compile(js_source)

print(docjs.call("hi")) # 輸出"Hi!"

一個更好的js引擎—splash

使用docker來執行,在瀏覽器上訪問。最大的優點:提供了十分方便的JS網頁渲染服務,提供了簡單的HTTP API,而且由於不需要瀏覽器程序,不會使用太多資源,和Selenium相比,這一點尤其突出。Splash的執行腳本是基於Lua語言編寫的,支持用戶自行編輯,但仍然可以通過HTTP API的方式在Python中調用,因此通過execute接口,可以顯示很多更復雜的網頁解析過程

表單與模擬登錄

在Python中使用Cookie

Python提供了Cookielib庫來對Cookie數據進行簡單的處理,這個模塊裏主要的類有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar等

requests的Cookie功能

除了cookiejar模塊,在抓取程序中使用更爲廣泛的是requests的Cookie功能,可以將字典結構信息作爲Cookie伴隨一次請求來發送

#!/usr/bin/env python
# encoding: utf-8

import requests
cookie = {
    'cookiefiled1': 'value1',
    'cookiefiled2': 'value2',
    # 更多cookie信息
}

headers = {
    'User-Agent': "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
}

url = 'https://www.douban.com'

requests.get(url, cookie=cookie, headers=headers)

通過Session獲取Cookie

查看網站,登錄的url何QuerySrting爲

在這裏插入圖片描述

用程序來登錄,並得到登錄後的會話

#!/usr/bin/env python
# encoding: utf-8

import requests.cookies

headers = {
    'User-Agent': "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
}

form_data = {
    'username': 'zengraoli',
    'password': 'Zeng123456@',
    'quickforward': 'yes',
    'handlekey': 'ls'
}

sess = requests.Session()
url = "https://www.1point3acres.com/bbs/member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes&inajax=1"
sess.post(url, headers=headers, data=form_data)

print(sess.cookies)
print(type(sess.cookies))

# 從主頁面中查看是否已經等了
home_url = "https://www.1point3acres.com/bbs/home.php?mod=space&do=home"
html_data = sess.get(url, headers=headers).text
print(html_data)

可以看到,訪問的home_url能夠對cookie進行保持

在這裏插入圖片描述

模擬登陸網站

假如遇到輸入驗證碼登錄的網站,比如微博、知乎等,則可以利用瀏覽器登錄後,得到的cookie來進行下一步操作

下面的例子則首先利用Selenium模擬瀏覽器來保存豆瓣登錄後的Cookie信息,用pickle保存到文件中

import selenium.webdriver
import pickle, time, os


class SeleDouban():
  _path_of_chromedriver = r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe'
  _browser = None
  _url_homepage = 'https://www.douban.com/'
  _cookies_file = 'douban-cookies.pkl'
  _header_data = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                  'Accept-Encoding': 'gzip, deflate, sdch, br',
                  'Accept-Language': 'zh-CN,zh;q=0.8',
                  'Connection': 'keep-alive',
                  'Cache-Control': 'max-age=0',
                  'Upgrade-Insecure-Requests': '1',
                  'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36',
                  }

  def __init__(self):
    self.initial()

  def initial(self):
    self._browser = selenium.webdriver.Chrome(self._path_of_chromedriver)
    self._browser.get(self._url_homepage)

    if self.have_cookies_or_not():
      self.load_cookies()
    else:
      print('Login first')
      time.sleep(30)
      self.save_cookies()

    print('We are here now')

  def have_cookies_or_not(self):
    if os.path.exists(self._cookies_file):
      return True
    else:
      return False

  def save_cookies(self):
    pickle.dump(self._browser.get_cookies(), open(self._cookies_file, "wb"))
    print("Save Cookies successfully!")

  def load_cookies(self):
    self._browser.get(self._url_homepage)
    cookies = pickle.load(open(self._cookies_file, "rb"))
    for cookie in cookies:
      self._browser.add_cookie(cookie)
    print("Load Cookies successfully!")

  def get_page_by_url(self, url):
    self._browser.get(url)

  def quit_browser(self):
    self._browser.quit()


if __name__ == '__main__':
  db = SeleDouban()
  time.sleep(10)
  db.get_page_by_url('https://accounts.douban.com/passport/setting')

  time.sleep(10)
  db.quit_browser()

得到cookie成功的信息如下

在這裏插入圖片描述

得到了cookie以後,就可以使用request加載本地的Cookie來完成一些操作,比如進入個人設置查看綁定的郵箱

import requests, pickle
from lxml.html import fromstring

headers = {
  'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) '
                'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'}
sess = requests.Session()
with open('douban-cookies.pkl', 'rb') as f:
  cookie_data = pickle.load(f) # 加載cookie信息
  # print(cookie_data)

for cookie in cookie_data:
  sess.cookies.set(cookie['name'], cookie['value']) # 爲session設置cookie信息

res = sess.get('https://accounts.douban.com/passport/setting', headers=headers).text # 訪問並獲得頁面信息
tree = fromstring(res)
profile = tree.xpath("//div[@class='account-form-raw']/div[@class='account-form-field']/span/text()")
print("當前用戶的郵箱信息爲:", profile[-1])

HTTP基本認證

HTTP基本認證會使瀏覽器彈出要求用戶輸入用戶名和密碼的窗口,並根據輸入的信息進行身份驗證,比如下面的示例網站

在這裏插入圖片描述

使用requests.auth模塊中的HTTPBasicAuth類即可通過該認證並下載最終圖片到本地

import requests
from requests.auth import HTTPBasicAuth

url = 'https://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx'

auth = HTTPBasicAuth('httpwatch', 'pw123') # 將用戶名和密碼作爲對象初始化的參數
resp = requests.post(url, auth=auth)

with open('auth-image.jpeg','wb') as f:
  f.write(resp.content)

驗證碼

通常驗證碼可以用下面三種形式來處理

  • 用OCR的方法
  • 手工打碼
  • 使用人工打碼服務

自己做一個圖片滑動驗證碼,請參考:圖片滑動驗證碼的生成

破解圖片驗證碼的代碼如下:

# 模擬瀏覽器通過滑動驗證的程序示例,目標是在登錄時通過滑動驗證
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image

def get_screenshot(browser):
  browser.save_screenshot('full_snap.png')
  page_snap_obj = Image.open('full_snap.png')
  return page_snap_obj

# 在一些滑動驗證中,獲取背景圖片可能需要更復雜的機制,
# 原始的HTML圖片元素需要經過拼接整理才能拼出最終想要的效果
# 爲了避免這樣的麻煩,一個思路就是直接對網頁截圖,而不是去下載元素中的img src


def get_image(browser):
  img = browser.find_element_by_class_name('geetest_canvas_img')  # 根據元素class名定位
  time.sleep(2)
  loc = img.loc
  size = img.size

  left = loc['x']
  top = loc['y']
  right = left + size['width']
  bottom = top + size['height']

  page_snap_obj = get_screenshot(browser)
  image_obj = page_snap_obj.crop((left, top, right, bottom))
  return image_obj

# 獲取滑動距離
def get_distance(image1, image2, start=57, thres=60, bias=7):
  # 比對RGB的值
  for i in range(start, image1.size[0]):
    for j in range(image1.size[1]):
      rgb1 = image1.load()[i, j]
      rgb2 = image2.load()[i, j]
      res1 = abs(rgb1[0] - rgb2[0])
      res2 = abs(rgb1[1] - rgb2[1])
      res3 = abs(rgb1[2] - rgb2[2])

      if not (res1 < thres and res2 < thres and res3 < thres):
        return i - bias
  return i - bias

# 計算滑動軌跡
def gen_track(distance):
  # 也可通過隨機數來獲得軌跡

  # 將滑動距離增大一點,即先滑過目標區域,再滑動回來,有助於避免被判定爲機器人
  distance += 10
  v = 0
  t = 0.2
  forward = []

  current = 0
  mid = distance * (3 / 5)
  while current < distance:
    if current < mid:
      a = 2.35
      # 使用浮點數,避免機器人判定
    else:
      a = -3.35
    s = v * t + 0.5 * a * (t ** 2)  # 使用加速直線運動公式
    v = v + a * t
    current += s
    forward.append(round(s))

  backward = [-3, -2, -2, -2, ]

  return {'forward_tracks': forward, 'back_tracks': backward}


def crack_slide(browser):  # 破解滑動認證
  # 點擊驗證按鈕,得到圖片
  button = browser.find_element_by_class_name('geetest_radar_tip')
  button.click()
  image1 = get_image(browser)

  # 點擊滑動,得到有缺口的圖片
  button = browser.find_element_by_class_name('geetest_slider_button')
  button.click()
  # 獲取有缺口的圖片
  image2 = get_image(browser)
  # 計算位移量
  distance = get_distance(image1, image2)
  # 計算軌跡
  tracks = gen_track(distance)
  # 在計算軌跡方面,還可以使用一些鼠標採集工具事先採集人類用戶的正常軌跡,將採集到的軌跡數據加載到程序中

  # 執行滑動
  button = browser.find_element_by_class_name('geetest_slider_button')
  ActionChains(browser).click_and_hold(button).perform()  # 點擊並保持

  for track in tracks['forward']:
    ActionChains(browser).move_by_offset(xoffset=track, yoffset=0).perform()
  time.sleep(0.95)
  for back_track in tracks['backward']:
    ActionChains(browser).move_by_offset(xoffset=back_track, yoffset=0).perform()

  # 在滑動終點區域進行小範圍的左右位移,模仿人類的行爲
  ActionChains(browser).move_by_offset(xoffset=-2, yoffset=0).perform()
  ActionChains(browser).move_by_offset(xoffset=2, yoffset=0).perform()

  time.sleep(0.5)
  ActionChains(browser).release().perform()  # 鬆開

def worker(username, password):
  browser = webdriver.Chrome(r'C:\Users\zeng\AppData\Local\Google\Chrome\Application\chromedriver.exe')
  try:
    browser.implicitly_wait(3)  # 隱式等待
    browser.get('your target login url')

    # 在實際使用時需要根據當前網頁的情況定位元素
    username = browser.find_element_by_id('username')
    password = browser.find_element_by_id('password')
    login = browser.find_element_by_id('login')
    username.send_keys(username)
    password.send_keys(password)
    login.click()

    crack_slide(browser)

    time.sleep(15)
  finally:
    browser.close()

if __name__ == '__main__':
  worker(username='yourusername', password='yourpassword')

在這裏插入圖片描述

Python與文本分析

jieba

國人開發的一箇中文分詞與文本分析工具,可以實現很多使用的文本分析處理,通過

pip install jieba

安裝

使用jieba分詞

使用jieba進行分詞非常方便

  • jieba.cut:接收3個參數,即待處理的字符串、是否採用全模式(cut_all)、HMM(是否使用HMM模型)
  • jieba.cut_for_search():接收2個參數,即待處理的字符串和HMM,該方法適用於搜索引擎構建倒排索引分詞,粒度比較細,使用頻率不高,使用如下

示例使用如下

#!/usr/bin/env python
# encoding: utf-8

"""
@version: ??
@author: zengraoli
@license: Apache Licence 
@contact: [email protected]
@site: 
@software: PyCharm
@file: jieba_1.py
@time: 2020/4/23 8:44
"""

import jieba

if __name__ == "__main__":
    seg_list = jieba.cut("這裏曾經有一座大廈", cut_all=True)
    print(" / ".join(seg_list))  # 全模式
    seg_list = jieba.cut("歡迎使用Python語言", cut_all=False)
    print(" / ".join(seg_list))  # 精確模式
    seg_list = jieba.cut("我喜歡吃蘋果,不喜歡吃香蕉。")  # 默認是精確模式
    print(" / ".join(seg_list))

分詞後的結果爲

在這裏插入圖片描述

jieba關鍵詞提取

基於TF-IDF算法的關鍵詞提取方法:jieba.analyse.extract_tags(),使用如下

import jieba.analyse
import jieba

if __name__ == "__main__":
    sentence = '''上海市(Shanghai),簡稱“滬”或“申”,有“東方巴黎”的美稱。是中國四個中央直轄市之一,也是中國第一大城市。是中國大陸的經濟、金融、貿易和航運中心。上海創造和打破了中國世界紀錄協會多項世界之最、中國之最。上海位於中國大陸海岸線中部的長江口,擁有中國最大的外貿港口、最大的工業基地。'''
    res = jieba.analyse.extract_tags(sentence, topK=5, withWeight=False, allowPOS=())
    print(res)

取出來的關鍵詞如下

在這裏插入圖片描述

jieba新建自定義分詞器

請參考:python中的jieba分詞使用手冊

其他的功能

自定義詞典、調整詞頻等

其他一些使用

#!/usr/bin/env python
# encoding: utf-8

"""
@version: ??
@author: zengraoli
@license: Apache Licence 
@contact: [email protected]
@site: 
@software: PyCharm
@file: jieba_1.py
@time: 2020/4/23 8:44
"""

from jieba import posseg
from jieba import tokenize

if __name__ == "__main__":
    words = posseg.cut("我不明白你這句話的意思") # posseg.dt爲默認磁性標註分詞器
    for word, flag in words:
        print('{}:\t{}'.format(word, flag))

    result = tokenize('它是站在海岸遙望海中已經看得見桅杆尖頭了的一隻航船') # tokenize方法會返回分詞結果中詞語在原文的起止位置
    for tk in result:
        print("word %s \t\t start: %d\t\t end: %d" % (tk[0], tk[1], tk[2]))

SnowNLP

是一個主打簡潔、使用的中文處理模塊,模仿TextBlib編寫,擁有更多的功能

SnowNLP中的主要方法如下:

#!/usr/bin/env python
# encoding: utf-8

"""
@version: ??
@author: zengraoli
@license: Apache Licence 
@contact: [email protected]
@site: 
@software: PyCharm
@file: jieba_1.py
@time: 2020/4/23 8:44
"""

from snownlp import SnowNLP

s = SnowNLP('我來自中國,喜歡吃餃子,愛好是游泳。') # 分詞
print(s.words)# 輸出 :['我', '來自', '中國', ',', '喜歡', '吃', '餃子', ',', '愛好', '是', '游泳', '。']
#  情感極性概率
print(s.sentiments) # positive的概率,輸出:0.9959503726200969
# 文字轉換爲拼音
print(s.pinyin) # 輸出:['wo', 'lai', 'zi', 'zhong', 'guo', ',', 'xi', 'huan','chi', 'jiao', 'zi', ',', 'ai', 'hao', 'shi', 'you', 'yong', '。']
s = SnowNLP(u'「繁體中文」的叫法在臺灣也很常見。')# 繁簡轉換
print(s.han) # 輸出:「繁體中文」的叫法在臺灣也很常見。

NLTK

提供了對語料與模型等的內置管理器

在這裏插入圖片描述

更多使用請參考:【Python+中文自然語言處理】(一) NLTK庫

文本分類與聚類

下面的例子使用NLTK做了一個簡單的分類任務—藉助內置的names語料庫,通過樸素貝葉斯分類來判斷一個輸入的名字是男名還是女名

def gender_feature(name):
   return {'first_letter': name[0],
           'last_letter': name[-1],
           'mid_letter': name[len(name) // 2]}
   # 提取姓名中的首字母、中位字母、末尾字母爲特徵


import nltk
import random
from nltk.corpus import names

# 獲取名字-性別的數據列表
male_names = [(name, 'male') for name in names.words('male.txt')]
female_names = [(name, 'female') for name in names.words('female.txt')]
names_all = male_names + female_names
random.shuffle(names_all)

# 生成特徵集
feature_set = [(gender_feature(n), g) for (n, g) in names_all]

# 拆分爲訓練集和測試集
train_set_size = int(len(feature_set) * 0.7)
train_set = feature_set[:train_set_size]
test_set = feature_set[train_set_size:]

classifier = nltk.NaiveBayesClassifier.train(train_set)
for name in ['Ann','Sherlock','Cecilia']:
   print('{}:\t{}'.format(name,classifier.classify(gender_feature(name))))

全文所涉及的代碼下載地址

https://download.csdn.net/download/zengraoli/12366948

參考鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章