20-3-18 pyhton爬虫3

80101815_p0.jpg
selenium 代理 多线程

高阶函数

python的一些高阶特性与js有点像,可以看这里的参考

代理

为了防止对单一ip的限制,有些时候往往需要使用代理,与本机代理差不多,换成其他ip与端口就行。

selenium

参考文档
在进行爬虫操作时,往往遇到一些比较难处理的内容,或者是由于网站对于爬虫限制严格,这时可以使用selenium来模拟人类操作。selenium也可以用于对于网站的测试。

前期准备

selenium包,浏览器对应的WebDriver 比如chrome的在这里

基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
# 创建driver
driver = webdriver.Chrome('webdriver的路径')
# 打开页面
driver.get("https://www.baidu.com/")
# 查找页面元素
elem = driver.find_element_by_id("kw")
# 清楚元素内默认内容
elem.clear()
# 输入内容 与 回车
elem.send_keys("123")
elem.send_keys(Keys.RETURN)
# 获取页面html代码
pagesource = driver.page_source
# 获取cookies
cookie = driver.get_cookies()
# 点击
elem.click()

查找元素

selenium提供了多种查找方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
一次查找多个元素 (这些方法会返回一个list列表)
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

比较方便的就是直接通过浏览器来直接获取xpath

比如chrome浏览器F12打开后通过直接移动到对应元素上右键,就有copy,选择copy xpath 就直接复制成功了 非常方便

多进程/线程

参考

进程消耗资源多,占有单独的内存,稳定性高。线程占用资源少,但共享进程内存,一旦崩溃就全部崩溃。

遇到计算密集型任务时。分配多进程任务时,一般不超过cpu核心数,一般来说计算密集型任务一般选择C语言这类消耗资源少,速度快的语言。I/O密集型任务一般选择python这类易读代码少的语言。

python存在GIL全局锁,难以实现多线程多核任务。

进程

unix linux的pc直接使用fork函数就行,win的系统需要使用multiprocessing包里的函数

process
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
Pool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from multiprocessing import Pool
import os, time, random

def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
queue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from multiprocessing import Process
import os
import time
from multiprocessing import Pool
from multiprocessing import Queue
def write(q):
print('write pid:%s', os.getpid())
for value in [1,3,4]:
print('write %s', value)
q.put(value)
time.sleep(1)
def read(q):
print('read pid:%s', os.getpid())
while 1:
value = q.get()
print('read %s', value)
if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start()
pr.start()
pw.join()
pr.terminate()

线程

threading
1
2
3
4
5
6
7
8
import threading
def threadloop():
print('thread %s'% threading.current_thread().name)
print('thread %s'%threading.current_thread().name)
t = threading.Thread(target=threadloop, name='LoopThread')
t.start()
t.join()

lock

线程由于共享资源 往往在计算过程中产生错误,如下代码就展示出结果并不一定为0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
balance = 0

def change_it(n):
global balance
balance = balance + n
balance = balance - n

def run_thread(n):
for i in range(100000):
change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

因此需要设置锁来限制

1
2
3
4
5
6
7
8

def run_thread(n):
for i in range(100000):
lock.acquire()
try:
change_it(n)
finally:
lock.release()
ThreadLocal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local_school = threading.local()

def process_student():
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))

def process_thread(stdname):
local_school.student = stdname
process_student()

t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
作者

Xingo

发布于

2020-03-18

更新于

2020-03-18

许可协议