0%

Python-网络操作

Python 进行网络操作、爬虫相关的实践。如:

  • socket:套接字的相关,实现不同主机的进程间的数据交换。
  • requests:基于 urllib 的 Python 第三方库,但比 urllib 更加方便易用。
  • lxml:数据解析,xpath 解析器解析 html,bs4 的罗嗦与不好维护,lxml 具有基于 C 的超越 bs4 的速度
    • BeautirulSoup:BS4:优雅地处理 html,but 打不过 lxml,OUT
  • scrapy:一套成熟的 Python 爬虫框架,抓取网站数据并提取结构化数据。
  • selenium:模拟浏览器的数据采集,web 应用程序自动化测试框架,主要用于 web 应用程序的测试。模拟真实用户对浏览器进行操作,适用于 js 渲染多的
  • you-get:一个 YouTube/Youku/Niconico 视频下载器,使用 Python3 编写。
  • pytesser:验证码破解
  • newscatcher:获取新闻资讯的工具包,它时刻监控者成千上万个新闻媒体并对其进行聚合,它包含丰富的 API 接口,开发者可以通过时间新闻源关键字等方式来获取新闻资讯。
  • aiohttp:基于 asyncio 的异步 HTTP 网络库。

概述

常识

爬虫:Spider:网络蜘蛛,自动化批量采集网络数据的程序

  • 前置知识:
    • HTML、JavaScript 基础
    • 网络协议 (POST/GET)
    • 正则表达式:re
    • xpath
  • 应用:
    - 数据挖掘、机器学习、图像处理等科学研究领域的数据获取
    - 产品研发的市场数据
    - 舆情监控数据

基本流程

  • HTML 请求
    • 工具:urllib3\requests\mechanize\selenium\splinter
    • 数据请求:
      • html:静态页面或动态页面,在网页上看到的内容都可以以特定的 HTML 标签得到。
      • js:找到包含内容的 js 代码串,然后通过正则表达式获得相应的内容,而不是解析 HTML 标签。
      • ajax:分页形式显示在网页上,需对网页进行交互操作后得到内容
      • app 的抓包
  • HTML 解析:
    • 工具:lxml\beautifulsoup4\re\pyquery
    • JSON 解析
    • css 选择器 class/id 定位
    • XPATH 路径选择
    • 正则表达式匹配
  • 存储
    • 缓存:Redis
    • 结构化存储至数据库、CSV、json
    • 网页判重
    • 信息抽取
    • 更新
  • 爬虫速度
    • 网络阻塞:
    • 多线程、任务调度、消息队列、分布式爬虫、
    • CPU 负载:
  • 反爬虫破解
    • 请求头中的字段,如 User-Agent、refer 等,
    • 用户登录认证
    • 用户行为:后台对访问 IP 或 User-Agent 有统计,超过一定阈值进行封锁,此时需要代理服务器,每隔几次请求,切换代理服务器。得控制好度,别把别人的网站搞坏了引起纠纷。
    • 代理池:保证爬虫的稳定性
    • API 接口
    • 数据为 ajax 请求,根据请求与确定的参数,模拟 http 请求,从响应中得到数据。
    • JS 加密反爬:ajax 动态加载数据 :Selenium+ChromeDriver
    • 基于 JavaScript 的反爬虫手段,主要是在响应数据页面之前,先返回一段带有 JavaScript 代码的页面,用于验证访问者有无 JavaScript 的执行环境,以确定使用的是不是浏览器
    • webdriver 识别
    • 图像识别、验证码识别,tesseract-ocr
    • APP 上的数据
    • mitmproxy 抓包
    • 反编译 APK,分析鉴权与 API
  • 安全性
    • http//网址/robots.txt
    • 站长工具
  • 匹配方式
    • re
    • xpath
  • 进阶
    • 爬虫策略
    • 异步 IO
    • 分布式爬虫

相关工具

  • 静态页面,就上 requests +lxml/beautifulSoup
  • 动态网站:大量js动态渲染,就上 Playwright/selenium
  • 复杂的、大型的就上scrapy
  • webscrapyer:一个谷歌插件,点点鼠标抓取数据。
  • portia:Docker 下的开源可视化爬虫工具
  • pyspider
  • creepy
  • pyquery

socket

socket:套接字的相关,实现不同主机的进程间的数据交换。

  • 传输层的网络编程,具体网络相关参考计算机网络的相关知识
  • 这里主要讨论 Python 的 TCP 通信
  • UDP 端口与 TCP 端口不冲突,即 UDP 的 9999 端口与 TCP 的 9999 端口可以各自绑定
  • TCP:建立可靠连接,通信双方都可以以流的形式发送数据。
  • UDP:无连接,只需要知道对方的 IP 地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。
  • Socket=IP address+TCP/UDP+port:IP 地址 + 协议 + 端口号
  • UDP 传输数据不可靠,但比 TCP 速度快。
1
2
3
4
5
6
7
8
9
10
11
conn = socket.socket(
family=AF_INET, # 网络类型
# - socket.AF_UNIX(UNIX 网络)
# - socket.AF_INET(基于 IPv4 协议的网络)
# - socket.AF_INET6(基于 IPv6 协议的网络)
type=SOCK_STREAM, # 网络 Sock 类型
- SOCK_STREAM(默认值,创建基于 TCP 协议的 socket)
- SOCK_DGRAM(创建基于 UDP 协议的 socket)
- SOCK_RAW(创建原始 socket)
proto=0, # 参数用于指定协议号,如果没有特殊要求,该参数默认为 0 ,并可以忽略
fileno=None)

基本使用

  • 客户端:主动发起连接的:主动连接服务器的 IP 与指定端口
  • 服务端:被动响应的:监听指定端口,对每个新的连接创建一个线程或进程来处理
    • 同一个端口,只能被一个 Socket 绑定
  • socket 连接具有唯一性:四项:服务器地址、服务器端口、客户端地址、客户端端口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import socket
socket.gethostname()

send # 发送数据
sendto() 用于 UDP 协议的通信
recv_xxx() #接收数据



# 客户端,192.168.1.88
import socket
s=socket.socket(socket.AF_INET, # AF_UNIX 或 AF_INET
socket.SOCK_STREAM, # SOCK_STREAM(tcp/ip) 或 SOCK_DGRAM(udp/ip)
protocal=0) # 默认为 0 即可
s.connect(('192.168.1.1',30000)) # #tuple:服务器的 IP 地址和端口号,ip 地址可用域名代替
print('--%s--' % s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
# 发送数据:
s.send(data)
print(s.recv(1024).decode('utf-8'))
s.close()

# 服务端,192.168.1.1
s=socket.socket()
s.bind(("192.168.1.1",30000))
s.listen() # 监听来自客户端的连接
while True:
c,addr=s.accept()
print(c,addr)
c.send("helloworld".encode("utf-8")) #向客户端发个信息
c.close() # 关闭连接


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听/绑定端口:
s.bind(('127.0.0.1', 9999)) # 小于 1024 的端口需要管理员权限才能绑定
s.listen(5) # 监听端口,最大连接数设为 5
print('Waiting for connection...')
while True: # 永久循环来接受连接
# 接受一个新连接:
sock, addr = s.accept() #accept()会等待并返回一个客户端的连接:
# 创建新线程来处理 TCP 连接:
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()

def tcplink(sock, addr):
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始 TCP 监听
s.accept() 被动接受 TCP 客户的连接,(阻塞式)等待连接的到来

客户端套接字函数
s.connect() 主动初始化 TCP 服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

公共用途的套接字函数
s.recv() 接收 TCP 数据
s.send() 发送 TCP 数据(send 在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的 TCP 数据(本质就是循环调用 send,sendall 在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用 send 直到发完)
s.recvfrom() 接收 UDP 数据
s.sendto() 发送 UDP 数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

面向文件的套接字的函数
s.makefile() 创建一个与该套接字相关的文件

requests

requests:请求网页信息的模块,基于 urllib 的 Python 第三方库,但比 urllib 更加方便易用。

urlib:用过 requests,再也不会考虑 urllib

  • 特点:
    • http 请求:自定义请求头、设置代理、支持重定向、支持 Session、Cookie 持久化、支持超时设置, 对 post 数据自动 urlencode;
    • http 响应:可获取响应的所有数据,如状态码、自动解码的响应内容、响应头中的各个字段;
    • 内置 JSON 解码器。

get-post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
url=''
response=requests.get(url,headers=headers,auth=('user':user1,'pass':pass1)) #发送请求,得到 response 这一服务器的响应数据。
response.url
response.status_code #状态码
response.reason #原因短语
response.headers.items() #响应头/响应首部
response.headers['content-type']
response.content #获得的内容的 bytes 对象
response.text
response.content.decode("utf-8")
response.encoding
response.json() #对于特定类型的响应,例如 JSON,可以直接获取
response.cookies['ts']
r = requests.post('http://httpbin.org/post', data = {'key':'value'})
r = requests.put('http://httpbin.org/put', data = {'key':'value'})
r = requests.delete('http://httpbin.org/delete')
# 查询参数
args = {"p": 4, "s": 20}
response = requests.get("http://fav.foofish.net", params = args)
response.url
1
2
3
4
5
6
7
8
9
如果网页的编码为 gbk,需要这样处理:
html = html.decode('gbk').encode('utf-8')

# 以 dict 传入 cookies 参数
cs={'token':'12345,'status':'working'}
r=requests.get(url.cookies=cs)

# 超时,2.5 秒
r = requests.get(url, timeout=2.5)

传入数据格式

1
2
3
4
5
6
r = requests.post(
my_url, json={"name": "chen"})

# 关键字参数 params 代表的是 query string(从字符“?”开始的就是 query string),
# 关键字参数 data 代表的是 body 中的 form,data关键字参数即 application/x-www-form-urlencoded
# 关键字参数 json 代表的是 body 中的 json,json关键字参数即 content-type:application/json
  • 代理设置:频繁抓取很容易被服务器屏蔽掉,或需爬取墙外的数据,需使用代理
1
2
3
4
5
6
import requests
proxies = {
'http': 'socks5://127.0.0.1:1080',
'https': 'socks5://127.0.0.1:1080',
}
requests.get('https://foofish.net', proxies=proxies, timeout=5)
  • 超时设置:requests 发送请求时,线程会阻塞,直到有响应返回时才会处理后续逻辑,为避免服务器一直未响应,需:
1
2
3
4
import requests
r=requests.get("http://www.google.com")
# 改为
r=requests.get("http://www.google.com",timeout=5) # 超时 5 秒时会报错
  • cookie 字符串放在 headers 中
1
2
3
4
headers={
'user-Agent':'..'
'Cookie':''
}
  • 将 cookie 字典传入请求方法的 cookies 参数接收
1
2
3
cookies = {"cookie 的 name":"cookie 的 value"}

requests.get(url,headers=headers,cookies=cookie_dict}
  • session
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 以 session 进行会话保持
s=requests.Session()
url=''
headers={
'user-Agent':'..'
'Cookie':''
}
post_data={
"username":"chen",
"password":"*****"
}
s.headers=headers
s.post(url,data=post_data)
res=session.get(url2,headers)
print(res)

lxml

lxml:解析网页信息的模块,使用 xpath 解析器解析 html

Beautifulsoup4:BS4:优雅地处理 html,but 打不过 lxml,OUT

  • bs4 的罗嗦与不好维护,lxml 具有基于 C 的超越 bs4 的速度
1
pip3 install Beautifulsoup4
1
2
3
4
5
6
7
from lxml import etree
import requests
html=requests.get('www.baidu.com').content.decode("utf-8")
dom_tree=etree.HTML(html)
links=dom_tree.xpath("//img/@src")
# html = etree.parse('./hello.html')
result=etree.tostring(links)

PyQuery:网页解析库,对 jQuery 熟悉者十分友好,不熟悉 jQuery,OUT.

结构

Element 类

  • XML 处理的核心类,看作 xml 的节点
    • 节点操作、节点属性操作、节点内文本操作
1
2
3
4
5
6
7
8
root=etree.Element('root')  #参数即节点名称
root.tag #节点属性
etree.tostring(root) #节点文本
child1=etree.SubElement(root,'child1') #创建子节点
root.rmove(child1)
root.clear()
child=root[0] #可视作列表操作
child1.getparent().tag

scrapy

scrapy:一套成熟的 Python 爬虫框架,抓取网站数据并提取结构化数据。

  • 教程:Scrapy1.5 超易懂
  • 轻量、简单、易用
  • 基于 Twisted 异步网络库处理网络通迅
  • scrapy+rq-queue 然后用 redis 来作队列就好。
  • 特点:
    • Twisted 异步网络库处理网络通讯
    • url 管理、url 解析

概述

组件

  • 引擎:engine:处理整个系统的数据流,触发事务(框架核心)

  • 调度器:Scheduler:调度 engine 发来的请求,将之加入队列,在 engine 再次请求时返回

    • 决定下一个要抓取的网址,并去除重复网址
  • 下载器:Downloader:下载网页数据,并将其传给 engine(基于 twisted)

  • 爬虫:Spiders:制定网页解析规则,从特定的网页中提取需要的信息,如实体(item)和 urls

  • 项目管道:Pipeline:处理爬虫从网页中抽取的实体,主要为:持久化实体、验证有效性,清除不必要的信息

    • 负责处理有蜘蛛从网页中抽取的项目,他的主要任务是清晰、验证和存储数据。当页面被蜘蛛解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
    • 对 pares 取出的数据进行去重、清洗
    • 清理 HTML 数据
    • 验证爬取的数据 (检查 item 包含某些字段)
    • 查重 (并丢弃)
    • 将爬取结果保存到数据库中:处理 engine 解析处理的 spider 返回的数据,并将数据持久化,即存入数据库或文件
  • 下载器中间件:Downloader Middlewares:处于引擎与下载器之间,以钩子的形式处理 Scrapy 引擎与下载器之间的请求及响应。

    • 位于 Scrapy 引擎和下载器之间的钩子框架,主要是处理 Scrapy 引擎与下载器之间的请求及响应。

    • 代替接收请求、处理数据的下载以及将结果响应给 engine

    • 实现一系列操作,例如使用代理、cookies、设置 timeout 等。

      1
      2
      3
      process_request(request, spider)
      process_response(request, response, spider)
      process_exception(request, exception, spider)
  • **爬虫中间件 (Spider Middlewares)***介于 Scrapy 引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。

    • 介于 Scrapy 引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛的响应输入和请求输出。
    • 调度、发送、接收、解析等一系列工作
  • **调度中间件 (Scheduler Middewares)***介于 Scrapy 引擎和调度之间的中间件,从 Scrapy 引擎发送到调度的请求和响应。

    • 介于 Scrapy 引擎和调度之间的中间件,从 Scrapy 引擎发送到调度的请求和响应。
  • 流程:

    1. 引擎从调度器中取出一个链接 (URL) 用于接下来的抓取
    2. 引擎把 URL 封装成一个请求 (Request) 传给下载器
    3. 下载器把资源下载下来,并封装成应答包 (Response)
    4. 爬虫解析 Response
    5. 解析出实体(Item),则交给实体管道进行进一步的处理
    6. 解析出的是链接(URL),则把 URL 交给调度器等待抓取
  • spider

    1
    2
    3
    4
    5
    6
    name
    allowed_domains
    start_urls
    custom_settings
    crawler
    settings

相关工具

scrapyd:通过 scrapyd-client 将不同网站的爬虫上传到不同的服务器,只需在 windows 上就能启动爬虫、暂停爬虫、修改爬虫

一台机子上既装 scrapyd 又装 scrapyd-client 是毫无意义且浪费资源的

基本命令

  • 新建项目:scrapy start project project1
1
2
3
4
5
6
7
8
9
tutorial/
scrapy.cfg # 部署配置文件
tutorial/ # Python 模块,代码写在这个目录下
__init__.py
items.py # 项目项定义文件
pipelines.py # 项目管道文件
settings.py # 项目设置文件
spiders/ # 我们的爬虫/蜘蛛 目录
__init__.py
1
2
3
4
5
6
7
8
9
10
scrapy genspider [options] <蜘蛛 name> <domain-taobao.com> # 根据蜘蛛模板创建蜘蛛
scrapy settings --get BOT_NAME # 查看设置
scrapy runspider aa.py # 通过.py 运行爬虫,而不必创建一个项目
scrapy fetch http://www.baidu.com > aa.html #爬不动数据,模拟一下,看看是不是异步传输啥的,如果 aa.html 没有想要的节点,那就是异步加载
scrapy view http://www.baidu.com #查看蜘蛛看到的和你看到的是否一致,用于排错
scrapy version
scrapy check 检查蜘蛛
scrapy list #有多少个爬虫(name)
scrapy crawl aa # 运行爬虫
scrapy crawl aa -o aa.json #将爬虫数据保存到 aa.json
1
2
# 创建项目
scrapy start porject poem #古诗文网的爬虫

poem-spiders 下写蜘蛛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import scrapy
class poem(scrapy.Spider):
name='poem_spider'
def start_requests(self): #下载页面
urls=[
# 'https://www.gushiwen.org/shiwen/default_0AA1.aspx',
'http://lab.scrapyd.cn/page/1/',
'http://lab.scrapyd.cn/page/2/',
]
for url in urls:
yield scrapy.Request(url=url,callback=self.parse)
def parse(self,response):
page=response.url.split('/')[-2]
filename='poem-{}.html'.format(page)
with open(filename,'wb') as f:
f.write(response.body)
self.log('保存文件:{}'.format(filename))

运行

1
scrapy crawl poem_spider  #poem_spider 为蜘蛛的 name

scrapy shell

  • shell 支持你在调试的过程中使用爬虫内的几乎所有工具,例如选择器等。
1
scrapy shell http://www.baidu.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
scrapy shell # 调试用
response.css("title").extract_first()
>scrapy shell www.baidu.com

[一大堆调试信息]
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x04836270>
[s] item {}
[s] request <GET http://www.baidu.com>
[s] settings <scrapy.settings.Settings object at 0x05461D50>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser

基本流程

打开页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import scrapy
class simpleUrl(scrapy.Spider):
name = "simpleUrl"
allowed_domains=["lab.scrapyd.cn"]
# 另外一种初始链接写法
def start_requests(self):
urls = [ #爬取的链接由此方法通过下面链接爬取页面
'http://lab.scrapyd.cn/page/1/',
'http://lab.scrapyd.cn/page/2/',
]
for url in urls:
#发送请求
yield scrapy.Request(url=url, callback=self.parse)
处理返回
parse(response)

import scrapy
class simpleUrl(scrapy.Spider):
name = "simpleUrl"
start_urls = [ #另外一种写法,无需定义 start_requests 方法
'http://lab.scrapyd.cn/page/1/',
'http://lab.scrapyd.cn/page/2/',
]
def parse(self, response):
page = response.url.split("/")[-2]
filename = 'mingyan-%s.html' % page
with open(filename, 'wb') as f:
f.write(response.body)
self.log('保存文件: %s' % filename)

提取数据 -Selector

Scrapy 的数据提取器:选择器 Selector,进行 CSS、Xpath 或正则的选择,

  • SelectorList 和 Selecto
  • 建立在 lxml 库上,解析速度与精度差不多
1
2
3
4
from scrapy.selector import Selector
html='<body>hello</body>'
selector=Selector(text=body)
data=selectors.xpath('//body/text()').extract_first()
  • .extract_first():提取 SelectorList 对象中第一个元素的内容。
  • .extract():如果是 SelectorList 对象使用,则返回包含内容的列表;如果是 Selector 使用,则返回它的内容。

css 提取

1
2
3
4
response.css('title').extract()[0] #css 为 title 的列表的第一项
response.css('title::text').extract_first() # ::text 表示取里面的数据
response.css("title::text")[0].extract()
response.css("title::text").re(r"")
  • 常见 css 表达式提取
1
2
3
4
5
6
response.css('.class_name a::attr(href)').extract()
response.css('#id_name img::attr(src)').extract()
标签名::attr(属性名)
response.css('p::text').extract() #p 标签的内容
标签唯一如 title 可直接取,不唯一得找最近的 class id 来取。
response.css(".post-content *::text").extract() #*
1
2
.class #class 选择器
#id #id 选择器
选择器示例示例说明CSS
.class.intro选择所有 class=”intro” 的元素1
#id#firstname选择所有 id=”firstname” 的元素1
**选择所有元素2
elementp选择所有

元素

1
element,elementdiv,p选择所有
元素和

元素

1
element elementdiv p选择
元素内的所有

元素

1
element>elementdiv>p选择所有父级是
元素的

元素

2
element+elementdiv+p选择所有紧接着
元素之后的

元素

2
[attribute][target]选择所有带有 target 属性元素2
[attribute=value][target=-blank]选择所有使用 target=”-blank” 的元素2
[attribute~=value][title~=flower]选择标题属性包含单词 “flower” 的所有元素2
[attribute|=language][lang|=en]选择一个 lang 属性的起始值=”EN” 的所有元素2
:linka:link选择所有未访问链接1
:visiteda:visited选择所有访问过的链接1
:activea:active选择活动链接1
:hovera:hover选择鼠标在链接上面时1
:focusinput:focus选择具有焦点的输入元素2
:first-letterp:first-letter选择每一个

元素的第一个字母

1
:first-linep:first-line选择每一个

元素的第一行

1
:first-childp:first-child指定只有当

元素是其父级的第一个子级的样式。

2
:beforep:before在每个

元素之前插入内容

2
:afterp:after在每个

元素之后插入内容

2
:lang(language)p:lang(it)选择一个 lang 属性的起始值=”it” 的所有

元素

2
element1~element2p~ul选择 p 元素之后的每一个 ul 元素3
[attribute^=value]a[src^=”https”]选择每一个 src 属性的值以 “https” 开头的元素3
[attribute$=value]a[src$=”.pdf”]选择每一个 src 属性的值以 “.pdf” 结尾的元素3
[attribute*=value]a[src*=”runoob”]选择每一个 src 属性的值包含子字符串 “runoob” 的元素3
:first-of-typep:first-of-type选择每个 p 元素是其父级的第一个 p 元素3
:last-of-typep:last-of-type选择每个 p 元素是其父级的最后一个 p 元素3
:only-of-typep:only-of-type选择每个 p 元素是其父级的唯一 p 元素3
:only-childp:only-child选择每个 p 元素是其父级的唯一子元素3
:nth-child(n)p:nth-child(2)选择每个 p 元素是其父级的第二个子元素3
:nth-last-child(n)p:nth-last-child(2)选择每个 p 元素的是其父级的第二个子元素,从最后一个子项计数3
:nth-of-type(n)p:nth-of-type(2)选择每个 p 元素是其父级的第二个 p 元素3
:nth-last-of-type(n)p:nth-last-of-type(2)选择每个 p 元素的是其父级的第二个 p 元素,从最后一个子项计数3
:last-childp:last-child选择每个 p 元素是其父级的最后一个子级。3
:root:root选择文档的根元素3
:emptyp:empty选择每个没有任何子级的 p 元素(包括文本节点)3
:target#news:target选择当前活动的#news 元素(包含该锚名称的点击的 URL)3
:enabledinput:enabled选择每一个已启用的输入元素3
:disabledinput:disabled选择每一个禁用的输入元素3
:checkedinput:checked选择每个选中的输入元素3
:not(selector):not(p)选择每个并非 p 元素的元素3
::selection::selection匹配元素中被用户选中或处于高亮状态的部分3
:out-of-range:out-of-range匹配值在指定区间之外的 input 元素3
:in-range:in-range匹配值在指定区间之内的 input 元素3
:read-write:read-write用于匹配可读及可写的元素3
:read-only:read-only用于匹配设置 “readonly”(只读) 属性的元素3
:optional:optional用于匹配可选的输入元素3
:required:required用于匹配设置了 “required” 属性的元素3
:valid:valid用于匹配输入值为合法的元素3
:invalid:invalid用于匹配输入值为非法的元素3

明确目标 -items.py

爬取 -xxspider.py

保存数据 -pipelines.py

管道:在 settings.py 中加入两行代码:

1
2
FEED_URI=u'/Users/apple/Documents/jianshu-hot.csv'
FEED_FORMAT='CSV'

selenium

selenium:模拟浏览器的数据采集,web 应用程序自动化测试框架,主要用于 web 应用程序的测试。模拟真实用户对浏览器进行操作,适用于 js 渲染多的

爬虫工具,对于由 js 或 ajax 生成 的网页,可使用 selenium 进行动态网页加载。

遇到的问题

  • Message: ‘chromedriver’ executable needs to be in PATH

  • chrome 浏览器输入 chrome://version/ 查看 chrome 版本

  • chromedriver 下载对应版本的 driver,如 79.0.3845.88 chromedriver_win32.zip

  • 解压至 chrome 安装的指定文件夹下,如 C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe

    1
    2
    chrome_drive=r"C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe"
    browser = webdriver.Chrome(executable_path=chrome_drive)#声明浏览器

005-you-get

you-get:一个 YouTube/Youku/Niconico 视频下载器,使用 Python3 编写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 常用
you-get -f http://www.meipai.com/media/437971164
you-get -i 查看可选择的清晰度与格式
you-get http://www.meipai.com/media/454570774
you-get -o E:/Desktop http://www.meipai.com/media/454570774
you-get --format=hd2 http://v.youku.com/v_show/id_XMTQ2NzQyMjY1Ng.html
you-get -p PotPlayerMini64.exe http://v.youku.com/v_show/id_XMTY0MTA4ODM1Mg==.html

# 批量下载
–input-file 参数读取 URL 列表文件即可(支持部分网站的播放列表下载,但支持的并不是很好。
# 暂停下载: Ctrl + C,文件在 .download 为扩展名的缓存文件
# 继续下载:重新执行下载任务,如果下载目录下有上次下载保存的缓存文件,则继续上次下载进度
# 强制重新下载:即使下载完成也会重新写入


# 下载一个[优酷视频专辑
you-get http://www.youku.com/playlist_show/id_25917721.html
#B 站
you-get https://www.bilibili.com/video/av14185130
#xml 弹幕文件,需转 ass 字幕文件

pytesser

pytesser:验证码破解

newscatcher

newscatcher:获取新闻资讯的工具包,它时刻监控者成千上万个新闻媒体并对其进行聚合,它包含丰富的 API 接口,开发者可以通过时间新闻源关键字等方式来获取新闻资讯。

  • 获取自己想的新闻资讯
  • 数据源丰富

urllib

urllib:已被 request 替代,用于执行各种 http 请求,获取网络资源

  • 不好用、不实用
  • Get:urllib 的 request 模块以 Get 请求发送到指定页面,返回的 http 响应为 URL 内容
1
2
3
from urllib import request
with request.urlopen('url') as f:
data=f.read()
  • Post:以 Post 将参数 data 以 bytes 形式传入请求。username=xxx&password=xxx
  • handler:如果还需要更复杂的控制,比如通过一个 Proxy 去访问网站,我们需要利用 ProxyHandler 来处理,

aiohttp

aiohttp:基于 asyncio 的异步 HTTP 网络库。

给博主来一杯卡布奇诺