爬虫相关

bs4

BeautifulSoup
soup = BeautifulSoup(r.content,'lxml')  # 载入
soup.prettify()  # 代码的格式化
soup.title
soup.p
hred = soup.find(name , attrs , recursive , text , **kwargs)  # 返回单个
hred = soup.find_all(name , attrs , recursive , text , **kwargs)  # 返回所有元素
a = soup.find("a", attrs={"id": "image"})  # 查找 id 为 image 的 a 标签

jsonpath

用于多层嵌套的复杂字典,想要根据key和下标来批量提取value情况

jsonpath语法规则

JSONPath 描述
$ 根节点
@ 现行节点
. 或 [] 取子节点
.. 递归匹配所有元素节点
* 选择所有符合条件的条件
[] 迭代器标示
[,] 支持迭代器中做多选
?() 支持过滤操作
() 支持表达式计算

jsonpath模块提取数据的方法

from jsonpath import jsonpath

ret = jsonpath(dict, 'jsonpath语法规则字符串') # 返回的是列表

参考代码

import requests
import jsonpath
import json

# 获取拉勾网城市json字符串
url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
headers = {"User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"}
response =requests.get(url, headers=headers)
html_str = response.content.decode()

# 把json格式字符串转换成python对象
jsonobj = json.loads(html_str)

# 从根节点开始,获取所有key为name的值
citylist = jsonpath.jsonpath(jsonobj,'$..name')

# 写入文件
with open('city_name.txt','w') as f:
    content = json.dumps(citylist, ensure_ascii=False)
    f.write(content)

lxml

xpath定位节点以及提取属性或文本内容的语法

表达式 描述
nodename 选中该元素。
/ 从根节点选取、或者是元素和元素间的过渡。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
text() 选取文本。
  • 选择所有的h2下的文本
    • //h2/text()
  • 获取所有的a标签的href
    • //a/@href
  • 获取html下的head下的title的文本
    • /html/head/title/text()
  • 获取html下的head下的link标签的href
    • /html/head/link/@href

xpath语法-节点修饰语法

路径表达式 结果
//title[@lang=”eng”] 选择lang属性值为eng的所有title元素
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()>1] 选择bookstore下面的book元素,从第二个开始选择
//book/title[text()=’Harry Potter’] 选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
  • 在xpath中,第一个元素的位置是1
  • 最后一个元素的位置是last()
  • 倒数第二个是last()-1
from lxml import etree
text = ''' 
<div> 
  <ul> 
    <li class="item-1">
      <a href="link1.html">first item</a>
    </li> 
    <li class="item-1">
      <a href="link2.html">second item</a>
    </li> 
    <li class="item-inactive">
      <a href="link3.html">third item</a>
    </li> 
    <li class="item-1">
      <a href="link4.html">fourth item</a>
    </li> 
    <li class="item-0">
      a href="link5.html">fifth item</a>
  </ul> 
</div>
'''

html = etree.HTML(text)

#获取href的列表和title的列表
href_list = html.xpath("//li[@class='item-1']/a/@href")
title_list = html.xpath("//li[@class='item-1']/a/text()")

#组装成字典
for href in href_list:
    item = {}
    item["href"] = href
    item["title"] = title_list[href_list.index(href)]
    print(item)

lxml模块中etree.tostring函数的使用

  • lxml.etree.HTML(html_str)可以自动补全标签
  • lxml.etree.tostring函数可以将转换为Element对象再转换回html字符串
  • 爬虫如果使用lxml来提取数据,应该以lxml.etree.tostring的返回结果作为提取数据的依据

selenium

driver对象定位标签元素获取标签对象的方法

find_element_by_id                         (返回一个元素)
find_element(s)_by_class_name             (根据类名获取元素列表)
find_element(s)_by_name                 (根据标签的name属性值返回包含标签对象元素的列表)
find_element(s)_by_xpath                 (返回一个包含元素的列表)
find_element(s)_by_link_text             (根据连接文本获取元素列表)
find_element(s)_by_partial_link_text     (根据链接包含的文本获取元素列表)
find_element(s)_by_tag_name             (根据标签名获取元素列表)
find_element(s)_by_css_selector         (根据css选择器来获取元素列表)
  • 注意:
    • find_element和find_elements的区别:
      • 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
      • find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表
    • by_link_text和by_partial_link_tex的区别:全部文本和包含某个文本
    • 以上函数的使用方法
      • driver.find_element_by_id('id_str')
from selenium import webdriver 

# 如果driver没有添加到了环境变量,则需要将driver的绝对路径赋值给executable_path参数
# driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')

# 创建一个配置对象
options = webdriver.ChromeOptions() 

# 开启无界面模式
options.add_argument("--headless") 
options.set_headless() # 另一种开启五戒面模式

# 禁用gpu
options.add_argument("--disable-gpu") 

# 使用代理ip
options.add_argument('--proxy-server=http://202.20.16.82:9527')

#修改默认UA头
options.add_argument('--user-agent=Mozilla/5.0 HAHA')

# 实例化带有配置的driver对象
# driver = webdriver.Chrome(chrome_options=options) 


# 如果driver添加了环境变量则不需要设置executable_path
driver = webdriver.Chrome()

# 向一个url发起请求
driver.get("https://mail.qq.com/cgi-bin/loginpage")


el = driver.find_element_by_tag_name('标签名')

# 通过定位获取的标签对象的text属性,获取文本内容
print(el.text) 

# 对定位到的标签对象进行点击操作
el.click()   

# 对定位到的标签对象输入数据
el.send_keys("数据")  

# 通过定位获取的标签对象的get_attribute函数,传入属性名,来获取属性的值
el.get_attribute("属性名")  



'''页面内的iframe中的内容无法直接操作,需要切换到iframe中 '''
# 根据id定位 frame元素
login_frame = driver.find_element_by_id('login_frame') 

# 转向到该frame中
driver.switch_to.frame(login_frame) 

# 获取当前所有的标签页的句柄构成的列表
current_windows = driver.window_handles  

# 根据标签页句柄列表索引下标进行切换标签页
driver.switch_to.window(current_windows[-1])  

# 返回列表,其中包含的是完整的cookie信息!不光有name、value,还有domain等cookie其他维度的信息。
driver.get_cookies() 

# 把cookie转化为字典
cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()} 

# 删除一条cookie
driver.delete_cookie("CookieName")  

# 删除所有的cookie
driver.delete_all_cookies()


js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句

# 执行js的方法
driver.execute_script(js) 

'''隐式等待针对的是元素定位,隐式等待设置了一个时间,在一段时间内判断元素是否定位成功,如果完成了,就进行下一步,否则会报超时加载'''
driver.implicitly_wait(10) # 隐式等待,最长等20秒 


# 把网页保存为图片,69版本以上的谷歌浏览器将无法使用截图功能
# driver.save_screenshot("itcast.png")

# 打印页面的标题
print(driver.title) 

# 当前标签页浏览器渲染之后的网页源代码
driver.page_source  

# 当前标签页的url
driver.current_url  

# 关闭当前标签页,如果只有一个标签页则关闭整个浏览器
driver.close()  

# 页面前进
driver.forward() 

# 页面后退
driver.back()  

# 退出模拟浏览器
driver.quit() # 一定要退出!不退出会有残留进程!
#滚动页面到elment上
def scroll_shim(driver, element):
    x = element.location['x']
    y = element.location['y']
    scroll_by_coord = 'window.scrollTo(%s,%s);' % (
        x,
        y
    )
    scroll_nav_out_of_way = 'window.scrollBy(0, -120);'
    driver.execute_script(scroll_by_coord)
    driver.execute_script(scroll_nav_out_of_way)

"""长页面截图"""
from selenium import webdriver 
import os
import time


def take_screenshot(driver):
    path = "1.png"
    # driver.maximize_window()
    # 返回网页的高度的js代码
    js_height = "return document.body.clientHeight"
    try:
        scroll_width = driver.execute_script('return document.body.parentNode.scrollWidth')
        scroll_height = driver.execute_script('return document.body.parentNode.scrollHeight')
        k = 1
        height = driver.execute_script(js_height)
        while True:
            if k * height < scroll_height:
                js_move = "window.scrollTo(0,{})".format(k * height)
                driver.execute_script(js_move)
                time.sleep(0.2)
                height = driver.execute_script(js_height)
                k += 1
            else:
                break
        # 将浏览器的宽高设置成完整页面的宽高
        driver.set_window_size(scroll_width, scroll_height)
        time.sleep(0.2)
        driver.save_screenshot("1.png")
        time.sleep(0.2)
        driver.get_screenshot_as_file("2.png")

    except Exception as e:
        print('take_screenshot',e)
        driver.close()
        driver.quit()

options = webdriver.ChromeOptions() 
options.add_argument("--headless")  # headless就是无界面模式,一定要使用这个模式,不然截不了全页面,只能截到你电脑的高度
options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36')
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(10)
driver.get("https://www.imzzj.com/")

take_screenshot(driver)
driver.close()
driver.quit()

appium

所需环境

参考

  • jdk 1.8 需配置好环境变量

  • nodejs、npm

  • android sdk export ANDROID_HOME=/usr/local/android-sdk-macosx tools/android update sdk --no-ui

  • python3.8

  • appium-desktop

  • appium-python-client 模块 pip3 install appium-python-client -i https://pypi.tuna.tsinghua.edu.cn/simple

  • appium-doctor npm install -g cnpm --registry=https://registry.npm.taobao.org && cnpm install -g appium-doctor

  • appium-inspector

  • 网易mumu (开启usb调试模式)

  • adb

使用方法

  1. 启动模拟器后连接模拟器测试是否正常adb kill-server && adb server && adb shell
  2. 查看要操作 app包名称/进程名 (当前为浏览器)
  3. 查看设备 adb devices # emulator-5554
  4. 启动 appium
  5. 启动Appium Inspector
  • Remote Path/wd/hub

  • platformName 系统名 Android

  • noReset 系统版本 True

  • deviceName 手机型号 emulator-5554

  • appPackage app的包名 com.android.browser

  • appActivity app的进程名 .BrowserActivity

  • 获取想要操作的 id/xpath 信息

Python 控制设备获取数据

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from appium import webdriver

# 初始化配置,设置Desired Capabilities参数
disired_caps = {
  "platformName": "Android",
  "deviceName": "emulator-5554",
  "appPackage": "com.android.browser",
  "appActivity": ".BrowserActivity",
  "noReset": True
}
# 新建一个driver
driver = webdriver.Remote("http://localhost:4723/wd/hub", disired_caps)
# 获取对应element
el = driver.find_element('id', 'com.android.browser:id/url')
# 点击
el.click()
# 发送数据
el.send_keys("https://www.baidu.com")
# 按键
driver.press_keycode(66)  # search 84,enter,66
time.sleep(5)
# 获取模拟器/手机的分辨率(px)
width = driver.get_window_size()['width']
height = driver.get_window_size()['height']
print(width, height)

# 计算滑动位置
start_x = width // 2  # 滑动的起始点的x坐标,屏幕宽度中心点
start_y = height // 3 * 2  # 滑动的起始点的y坐标,屏幕高度从上开始到下三分之二处
distance = height // 2  # y轴滑动距离:屏幕高度一半的距离
end_x = start_x # 滑动的终点的x坐标
end_y = start_y-distance # 滑动的终点的y坐标

# appium滑动的函数 从(start_x, start_y)滑动到(end_x, end_y)
driver.swipe(start_x, start_y, end_x, end_y)
driver.close_app()

MitmProxy

pip install mitmproxy

收集设置代理地址为主机ip:8080

mitmdump -p 8080

mitmdump -p 8080 -s mitm.py

def response(flow):
    # 如果经过中间人的请求中有以url或者url1开头请求,我就解析它的响应
    if '.webp?' not in flow.request.url:
        print(f"url: {flow.request.url}")
        print(f"data: {flow.response.text}")


文章作者: 子杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 子杰 ! !
评论
 上一篇
Django Django
Django 是一个由 Python 编写的一个开放源代码的 Web 应用框架。Django 本身基于 MVC 模型,即 Model(模型)+ View(视图)+ Controller(控制器)设计模
2022-03-03
下一篇 
Python发起URL请求 Python发起URL请求
requests是一个很实用的Python HTTP客户端库,编写爬虫和测试服务器响应数据时经常会用到。可以说,Requests 完全满足如今网络的需求
2022-03-03
  目录