Python爬虫笔记

爬虫-scrawler

分类

  • 网页爬虫 从PC端访问网站从而爬取内容,大部分是html格式(所以耗费流量和时延较多,同时由于html结构经常变化,维护成本高),可能需要以下技能点
    • 正则表达式 用于简单的定位元素
    • XPATH来定位dom元素 用于定位复杂的元素
    • selenium 通过自动化浏览器交互来定位元素
    • js语法 搭配selenium使用,一般在处理动态生成的dom或模拟动态事件使用,一些情况下需要使用selenium执行js语句才能获取需要的数据
    • 抓包 浏览器请求网页时可能同一个网站请求了多个网页和资源,而所需要的数据在这些资源中,不是在当前浏览的html页面里,需要抓包定位数据
  • 移动端爬虫 从移动端访问网站特殊接口从而爬取内容,一般是json格式(耗费流量较少,易于处理,但是分析复杂,技术难度高),可能需要以下技能点
    • 抓包工具 如fiddler/burpsuite 用于捕获http/https请求
    • 二进制逆向分析 有时候抓包的数据中会有比较复杂的加解密操作,需要从二进制进行分析

说明1:企业一般使用网页爬虫,技术难度稍微简单一些,爬取的都是公开数据,也就是用户操作浏览器时可以看到的数据。大型网站也会有反爬虫机制,因此做爬虫也是对抗过程,比如滑动验证/图形验证码/图形化数据/代理检测/header检测/访问频率检测等手段
说明2:抓包工具可以用来检验爬虫发的数据包的request和response是否正确,用于调试爬虫脚本

python爬虫常用库

  • requests/urllib/urllib2 执行http请求,url/base64编码解码等操作
  • selenium 自动化浏览器交互,xpath定位元素,动态执行js
  • lxml 用于解析html,xpath定位元素
  • BeautifulSoup 封装和简化了xpath定位元素

xpath语法

http://www.w3school.com.cn/xpath/xpath_syntax.asp
https://www.baidu.com为例

基本语法
/                   子节点
//                  根节点
nodename            节点                   //input
@attrib             属性                   //input[@type]
.                   当前节点                //input/.         //input[@type='submit']/.
..                  父节点                 //input/..        //input[@type='submit']/..
[]                  匹配元素下标            //input[1]        //input[@type='submit'][1]
last()              最后一个下标            //input[last()]   //input[last()-1]  
position()          当前下标               //input[position()<3]
*                   任何元素               //form[@id='form']/*
@*                  任何有属性的元素        //form[@*] 

运算符
||                  多个xpath路径          //form | //input              
+ - * div mod       数学计算
> = < != >= <=      条件表达式             //input[@type='hidden'][@value=8]
or and              逻辑表达式             //input[@name='ie' or @name='f']

python发送http请求

以urllib为例
python2 import urllib as urllib_
python3 import urllib.request as urllib_

设置代理

opener = urllib_.build_opener(urllib_.ProxyHandler({
    "http": proxy,
    "https": proxy,
}))
response = opener.open(urllib_.Request(url)).read()

设置header

headers = {
    'User-Agent': 'Mozilla/5.0'
}
opener = urllib_.build_opener()
response = opener.open(urllib_.Request(url, headers=headers)).read()

GET请求

opener = urllib_.build_opener()
response = opener.open(urllib_.Request(url)).read()

POST请求

postata = 'abc'
opener = urllib_.build_opener()
response = opener.open(urllib_.Request(url, data=postdata)).read()

selenium

selenium支持IE/Firefox/Chrome,在配置python+selenium环境时首先pip安装selenium,同时下载合适的内核,如chrome为http://chromedriver.storage.googleapis.com/index.html。不知道下载哪个内核可以看运行时报错信息

学习步骤

最简单的爬虫的核心代码

#! /usr/bin/env python
# # -*- coding: utf-8 -*-

import datetime
import hashlib
import json
import logging
from lxml import etree
import os
import random
import re
import socket
import ssl
import sys
import threading
import threadpool
import time


def RequestWithDefProxy(url, headers, postdata, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
    try:
        opener = urllib_.build_opener()
        content = opener.open(urllib_.Request(url, headers=headers, data=postdata), timeout=timeout).read()
        return content
    except Exception as e:
        print(url, e)
        return None
    
response = RequestWithDefProxy('http://tu.duowan.com/tag/27812.html', dict(), None)
html = etree.HTML(response)
items = html.xpath('//li[@class="box"]')
for item in items:
    suburl = item.xpath('a/img/@src')[0]
    filename = os.path.basename(suburl)
    subresponse = RequestWithDefProxy(suburl, "", None)
    if subresponse is not None:
        with open(filename, 'wb') as img:
            img.write(subresponse)

要点:

  • 实现get请求和post请求
  • 使用xpath在html中定位元素
  • 将RequestWithDefProxy得到的数据保存为html然后分析xpath

....

....

....

....

....

selenium使用

安装python+selenium

安装python接口:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple selenium

选择浏览器并安装driver

selenium -> driver -> chrome

Firefox Chrome Ie Edge Opera Safari 
headless: 
   Firefox   geckodriver
   Chrome    chromedriver

http://chromedriver.storage.googleapis.com/index.html
https://github.com/mozilla/geckodriver/releases

headless

# headless chrome
from selenium import webdriver
options = webdriver.chrome.options.Options()
options.add_argument('--headless')
driver = webdriver.Chrome(chrome_options=options)
driver.get("http://www.baidu.com")
baiduyixia = driver.find_element_by_xpath("//input[@type='submit']")
keyword = driver.find_element_by_xpath("//input[@id='kw']")
print(baiduyixia, keyword)

# headless firefox
from selenium import webdriver
options = webdriver.firefox.options.Options()
options.add_argument('--headless')
driver = webdriver.Firefox(firefox_options=options)
driver.get("http://www.baidu.com")
baiduyixia = driver.find_element_by_xpath("//input[@type='submit']")
keyword = driver.find_element_by_xpath("//input[@id='kw']")
print(baiduyixia, keyword)

4.元素选取

find_element_*     find_elements_*
id定位:find_element_by_id()
name定位:find_element_by_name()
class定位:find_element_by_class_name()
link定位:find_element_by_link_text()
partial link定位:find_element_by_partial_link_text()
tag定位:find_element_by_tag_name()
xpath定位:find_element_by_xpath()
css定位:find_element_by_css_selector()

browser.get("http://www.baidu.com")
#########百度输入框的定位方式##########
#通过id方式定位
browser.find_element_by_id("kw").send_keys("selenium")
#通过name方式定位
browser.find_element_by_name("wd").send_keys("selenium")
#通过tag name方式定位
browser.find_element_by_tag_name("input").send_keys("selenium")
#通过class name方式定位
browser.find_element_by_class_name("s_ipt").send_keys("selenium")
#通过CSS方式定位
browser.find_element_by_css_selector("#kw").send_keys("selenium")
#通过xpath方式定位
browser.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
############################################
browser.find_element_by_id("su").click()


<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
通过link text定位:
dr.find_element_by_link_text("新闻")
dr.find_element_by_link_text("hao123")
通过link text定位:
dr.find_element_by_partial_link_text("新")
dr.find_element_by_partial_link_text("hao")
dr.find_element_by_partial_link_text("123")
  1. 操作
implicitly_wait:等待
current_url:获取当前url
click:点击
send_keys:模拟按键   
clear:文本置空  
text:获取文本
title:
page_source:渲染后的html
id:获取id
execute_script:执行js
execute_async_script
get_attribute:获取属性
get_screenshot_as_base64  元素也可以截图
get_screenshot_as_file
get_screenshot_as_png

search_text = driver.find_element_by_id('kw')
search_text.send_keys('selenium')
search_text.submit()

driver.find_element_by_id("user_name").send_keys(Keys.TAB) 
time.sleep(3) 
driver.find_element_by_id("user_pwd").send_keys("123456")
driver.find_element_by_id("user_pwd").send_keys(Keys.ENTER)
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
driver.find_element_by_id("login").send_keys(Keys.ENTER) 
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')

click() 单击
context_click()  右击;
move_to_element()  鼠标悬停。

driver.get("https://www.baidu.cn")
# 定位到要悬停的元素
above = driver.find_element_by_link_text("设置")
# 对定位到的元素执行鼠标悬停操作
ActionChains(driver).move_to_element(above).perform()
  1. frame切换
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
print(source)
try:
    logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
    print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo.text)

driver.get("http://www.126.com")
driver.switch_to.frame('x-URS-iframe')
driver.find_element_by_name("email").clear()
driver.find_element_by_name("email").send_keys("username")
driver.find_element_by_name("password").clear()
driver.find_element_by_name("password").send_keys("password")
driver.find_element_by_id("dologin").click()
driver.switch_to.default_content()
  1. windows切换
driver.get("http://www.baidu.com")
# 获得百度搜索窗口句柄
sreach_windows = driver.current_window_handle
driver.find_element_by_link_text('登录').click()
driver.find_element_by_link_text("立即注册").click()
# 获得当前所有打开的窗口的句柄
all_handles = driver.window_handles
# 进入注册窗口
for handle in all_handles:
    if handle != sreach_windows:
        driver.switch_to.window(handle)
        print('now register window!')
        driver.find_element_by_name("account").send_keys('username')
        driver.find_element_by_name('password').send_keys('password')
        time.sleep(2)
        # ……
  1. 警告框
from selenium.webdriver.common.action_chains import ActionChains
driver.get('http://www.baidu.com')
# 鼠标悬停至“设置”链接
link = driver.find_element_by_link_text('设置')
ActionChains(driver).move_to_element(link).perform()
# 打开搜索设置
driver.find_element_by_link_text("搜索设置").click()
# 保存设置
driver.find_element_by_class_name("prefpanelgo").click()
time.sleep(2)
# 接受警告框
driver.switch_to.alert.accept()

9.下拉框选择

from selenium.webdriver.support.select import Select
driver.get('http://www.baidu.com')
# 鼠标悬停至“设置”链接
driver.find_element_by_link_text('设置').click()
sleep(1)
# 打开搜索设置
driver.find_element_by_link_text("搜索设置").click()
sleep(2)
# 搜索结果显示条数
sel = driver.find_element_by_xpath("//select[@id='nr']")
Select(sel).select_by_value('50')  # 显示50条
  1. cookie操作
add_cookie
get_cookies
delete_all_cookies
delete_cookie
driver.get("http://www.youdao.com")
# 获得cookie信息
cookie= driver.get_cookies()
# 将获得cookie的信息打印
print(cookie)

driver.get("http://www.youdao.com")
# 向cookie的name 和value中添加会话信息
driver.add_cookie({'name': 'key-aaaaaaa', 'value': 'value-bbbbbb'})
# 遍历cookies中的name 和value信息并打印,当然还有上面添加的信息
for cookie in driver.get_cookies():
    print("%s -> %s" % (cookie['name'], cookie['value']))
  1. js调用
driver.get("http://www.baidu.com")
# 设置浏览器窗口大小
driver.set_window_size(500, 500)
# 搜索
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
sleep(2)
# 通过javascript设置浏览器窗口的滚动条位置
js="window.scrollTo(100,450);"
driver.execute_script(js)
sleep(3)


输入文本:
# 第一种方式:模拟键盘信息
keyword.send_keys("测试一下")
baiduyixia.click()
# 第二种方式:执行js
driver.execute_script('document.getElementById("kw").value="bbb"')

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 上网原理 1、爬虫概念 爬虫是什麽? 蜘蛛,蛆,代码中,就是写了一段代码,代码的功能从互联网中提取数据 互联网: ...
    riverstation阅读 7,620评论 1 2
  • 1、requests.get/post(url,headers = headers, params = param...
    XilinxYY阅读 332评论 0 0
  • urllib提供了一系列用于操作URL的功能。 from urllib import request #引用ur...
    SWJTU_CC阅读 277评论 1 0
  • HTTP基本原理 URI、URL、URN(Uninform Resource) URI(Identifier):统...
    GHope阅读 2,014评论 2 26
  • 学习爬虫记笔记实例: #!/usr/bin/env python3 #coding:utf-8 import ur...
    dinglangping阅读 282评论 1 0