1.request模块他只能获取到服务器返回的数据,如果数据中包含js代码,他只会将js代码原封不动的返回。
是无法执行js代码。
如果遇到一些网页的内容是通过服务器返回的js代码,流浪器执行后得到内容这样的形式,我们是无法获取数据的。
2.用selenium+phantomjs就可以执行这些js代码。得到页面内容。
from selenium import webdriver
base_url = ‘http://fanyi.youdao.com/’
driver = webdriver.PhantomJS()
driver.get(base_url)
time.sleep(0.5)
html = driver.page_source
return HtmlResponse(url=request.url,body=html,encoding=‘utf-8’,request=request)
遇到的反爬:
1,user-agent的伪装。
2.封ip,可以使用代理。
3.使用验证码。手动输入验证码。
4.动态html页面(数据加密=js代码里面做了加密操作。)
html===》js链接+css链接==》分别请求这些链接,得到这些文件的内容===》就把他通过html语法完美呈现。
滑动加载:
1,分析ajax请求。
2.宽度:1000
高度:30000
time.sleep(10)
多线程爬虫实现
1.程序>=进程>线程
程序:由源代码生成的可执行应用。
进程:一个正在运行的程序可以看做一个进程
线程:进程中独立运行的代码段
多线程开启方法:
1.利用
t = threading.Thread(target=方法名,args=(param,))
t.start()
启动线程之后,该线程就会执行target参数对应方法的内容,该方法执行结束,该线程消亡。
2.创建线程类,之后实例化这个类,在调用start方法
(1)写一个类
(2)继承threading.Thread
(3)重写run方法。
run方法就是该线程类启动后执行的内容。
(4)如果想要传参数。就是这个类实例化的时候带参。
在定义init方法的时候,先调用父类的init方法:super().init()/threading.Thread.init(self)
3.threading.enumerate()可以查看线程数量。
4.线程名称,就是该线程的name变量,t.name
5.线程的5中状态。
6. 多线程和多进程
一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程(资源比进程少),使得多线程程序并发性更高。进程在执行过程中拥有独立的内存单元,而多个线程共识这段儿内存空间。线程不能独立运行,必需依存进程。
线程的执行开销小,但不利于资源的管理和保存。进程正好相反。
第一种方法:
import multiprocessing#threading
p2=multiprocessing.Process(target=run,args=(‘wupeiqi’,))
p2.start()
第二种方法:创建一个进程类
from multiprocessing import Process
import time,random
import os
class Run(Process):
def init(self,name):
# super().init()
Process.init(self)
self.name=name
def run(self):
print(os.getppid(),os.getpid())
print(’%s is running’ %self.name)
# time.sleep(random.randint(1,3))
print(’%s is run end’ %self.name)
if name == ‘main’:
p1=Run(‘alex’)
p2=Run(‘wupeiqi’)
p3=Run(‘yuanhao’)
p1.start()
p2.start()
p3.start()
print('主进程',os.getpid(),os.getppid())
7.多线程开发中遇到的问题
线程不安全问题,就是线程之间对公共资源进行操作时,会造成公共资源的混乱。
解决办法:互斥锁。
metux = threading.Lock()
metuxFlag = metux.acquire()
if metuxFlag:
#操作公共资源的代码
metux.release()
8.死锁:
有两种情况:
(1)同一个线程先后试图获得两把锁。
解决的办法:获得一把锁之后,先释放该锁,才能继续获取锁。
(2)两个线程对同一个资源的两部分同时进行操作,该资源是加了锁的,使得这两个线程都获得了锁,但又无法释放锁。
解决办法:避免出现两个线程同时对公共资源的两部分操作的情况发生。
9.用消息队列创建多线程思路:
前提是,你已经有一个线程类了。
(1)在main里面创建一个公共的queue,将页码添加到queue中
queue = Queue()
for i in range(1,100):
queue.put(i)
(2)定义爬取线程的list,可以在这个list中指定创建多少个线程进行爬取。
crawl_name_list = [‘aa’,‘bb’,‘cc’,‘dd’,‘ee’]
for name in crawl_name_list:
t = tencent_down(base_url,queue,name)
t.start()
(3)接下来需要在run方法里面添加从queue中获取内容的代码
while True:
if self.q.empty():
break
#获取要下载的页的页码
page = self.q.get()
#拼接url
url = self.url+str(page)
#发送请求
reposne = requests.get(url,headers=headers)
(4)还要注意的是,将queue当做一个参数传入线程类。保证每个线程都是共同使用的这个queue
def init(self,url,queue,name):
super().init()
self.url = url
self.q = queue
self.name = name
(5)如果你想要查看一下执行的时间,必须保证每个线程都执行完毕之后,在用time.time()去记录执行结束后的时间。
if name == ‘main’:
queue = Queue()
for i in range(1,100):
queue.put(i)
# https://careers.tencent.com/search.html?index=2
base_url = ‘https://careers.tencent.com/search.html?index=’
#这个list主要用来设置用几个线程去完成任务
crawl_name_list = [‘aa’,‘bb’,‘cc’,‘dd’,‘ee’]
thread_list=[]
for name in crawl_name_list:
t = tencent_down(base_url,queue,name)
t.start()
thread_list.append(t)
#join方法作用是阻塞主线程,直到i线程执行完毕。
for i in thread_list:
i.join()
end_time = time.time()
print(end_time-start_time)
Scrapy 框架初步
Scrapy Engine(引擎)
Scheduler(调度器)
Downloader(下载器)
Spider(爬虫)
Item Pipeline(管道)
Downloader Middlewares
自定义请求头:
def process_request(self, request, spider):
ua = UserAgent()
headers = {
‘User-Agent’:ua.random
}
response = requests.get(request.url,headers=headers)
# return response
return HtmlResponse(url = requests.url,bady = response.text,encoding=‘utf-8’,request = request)