python爬虫归纳_【知识归纳】史上最全的Python爬虫抓取技巧总结

2023-11-08

原标题:【知识归纳】史上最全的Python爬虫抓取技巧总结

一、最基本的抓站

import urllib2

content = urllib2.urlopen('http://XXXX').read()

二、使用代理服务器

这在某些情况下比较有用,比如IP被封了,或者比如IP访问的次数受到限制等等。

import urllib2

proxy_support = urllib2.ProxyHandler({'http':'http://XX.XX.XX.XX:XXXX'})

opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)

urllib2.install_opener(opener)

content = urllib2.urlopen('http://XXXX').read()

三、需要登录的情况

登录的情况比较麻烦我把问题拆分一下:

1、cookie的处理

import urllib2, cookielib

cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar())

opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)

urllib2.install_opener(opener)

content = urllib2.urlopen('http://XXXX').read()

是的没错,如果想同时用代理和cookie,那就加入proxy_support然后operner改为

opener = urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler)

2、表单的处理

登录必要填表,表单怎么填?首先利用工具截取所要填表的内容。

比如我一般用firefox+httpfox插件来看看自己到底发送了些什么包这个我就举个例子好了,以verycd为例,先找到自己发的POST请求,以及POST表单项:

9ec499cdc133099561bd06b393ff5a66.png

可以看到verycd的话需要填username,password,continueURI,fk,login_submit这几项,其中fk是随机生成的(其实不太随机,看上去像是把epoch时间经过简单的编码生成的),需要从网页获取,也就是说得先访问一次网页,用正则表达式等工具截取返回数据中的fk项。continueURI顾名思义可以随便写,login_submit是固定的,这从源码可以看出。还有username,password那就很显然了。

好的,有了要填写的数据,我们就要生成postdata

import urllib

postdata=urllib.urlencode({

'username':'XXXXX',

'password':'XXXXX',

'continueURI':'http://www.verycd.com/',

'fk':fk,

'login_submit':'登录'

})

然后生成http请求,再发送请求:

req = urllib2.Request(

url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',data = postdata

)

result = urllib2.urlopen(req).read()

3、伪装成浏览器访问

某些网站反感爬虫的到访,于是对爬虫一律拒绝请求。这时候我们需要伪装成浏览器,这可以通过修改http包中的header来实现:

headers = {

'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'

}

req = urllib2.Request(

url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',data = postdata,

headers = headers

)

4、反”反盗链”

某些站点有所谓的反盗链设置,其实说穿了很简单,就是检查你发送请求的header里面,referer站点是不是他自己,所以我们只需要像3.3一样,把headers的referer改成该网站即可,以黑幕著称地cnbeta为例:

headers = {

'Referer':'http://www.cnbeta.com/articles'

}

headers是一个dict数据结构,你可以放入任何想要的header,来做一些伪装。例如,有些自作聪明的网站总喜欢窥人隐私,别人通过代理访问,他偏偏要读取header中的X-Forwarded-For来看看人家的真实IP,没话说,那就直接把X-Forwarde-For改了吧,可以改成随便什么好玩的东东来欺负欺负他,呵呵。

5、终极绝招

有时候即使做了3.1-3.4,访问还是会被据,那么没办法,老老实实把httpfox中看到的headers全都写上,那一般也就行了。 再不行,那就只能用终极绝招了,selenium直接控制浏览器来进行访问,只要浏览器可以做到的,那么它也可以做到。类似的还有pamie,watir,等等等等。

四、多线程并发抓取

单线程太慢的话,就需要多线程了,这里给个简单的线程池模板 这个程序只是简单地打印了1-10,但是可以看出是并发地。

from threading import Thread

from Queue import Queue

from time import sleep

#q是任务队列

#NUM是并发线程总数

#JOBS是有多少任务

q = Queue()

NUM = 2

JOBS = 10

#具体的处理函数,负责处理单个任务

def do_somthing_using(arguments):

print arguments

#这个是工作进程,负责不断从队列取数据并处理

def working():

while True:

arguments = q.get()

do_somthing_using(arguments)

sleep(1)

q.task_done()

#fork NUM个线程等待队列

for i in range(NUM):

t = Thread(target=working)

t.setDaemon(True)

t.start()

#把JOBS排入队列

for i in range(JOBS):

q.put(i)

#等待所有JOBS完成

q.join()

五、验证码的处理

碰到验证码咋办?这里分两种情况处理:

google那种验证码,凉拌

简单的验证码:字符个数有限,只使用了简单的平移或旋转加噪音而没有扭曲的,这种还是有可能可以处理的,一般思路是旋转的转回来,噪音去掉,然后划分单个字符,划分好了以后再通过特征提取的方法(例如PCA)降维并生成特征库,然后把验证码和特征库进行比较。这个比较复杂,一篇博文是说不完的,这里就不展开了,具体做法请弄本相关教科书好好研究一下。

事实上有些验证码还是很弱的,这里就不点名了,反正我通过2的方法提取过准确度非常高的验证码,所以2事实上是可行的。

六、gzip/deflate支持

现在的网页普遍支持gzip压缩,这往往可以解决大量传输时间,以VeryCD的主页为例,未压缩版本247K,压缩了以后45K,为原来的1/5。这就意味着抓取速度会快5倍。

然而python的urllib/urllib2默认都不支持压缩,要返回压缩格式,必须在request的header里面写明’accept-encoding’,然后读取response后更要检查header查看是否有’content-encoding’一项来判断是否需要解码,很繁琐琐碎。如何让urllib2自动支持gzip, defalte呢?

其实可以继承BaseHanlder类,然后build_opener的方式来处理:

import urllib2

from gzip import GzipFile

from StringIO import StringIO

class ContentEncodingProcessor(urllib2.BaseHandler):

"""A handler to add gzip capabilities to urllib2 requests """

# add headers to requests

def http_request(self, req):

req.add_header("Accept-Encoding", "gzip, deflate")

return req

# decode

def http_response(self, req, resp):

old_resp = resp

# gzip

if resp.headers.get("content-encoding") == "gzip":

gz = GzipFile(

fileobj=StringIO(resp.read()),

mode="r"

)

resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code)resp.msg = old_resp.msg

# deflate

if resp.headers.get("content-encoding") == "deflate":

gz = StringIO( deflate(resp.read()) )

resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code) # 'class to add info() andresp.msg = old_resp.msg

return resp

# deflate support

import zlib

def deflate(data): # zlib only provides the zlib compress format, not the deflate format;

try: # so on top of all there's this workaround:

return zlib.decompress(data, -zlib.MAX_WBITS)except zlib.error:

return zlib.decompress(data)

然后就简单了,

encoding_support = ContentEncodingProcessor

opener = urllib2.build_opener( encoding_support, urllib2.HTTPHandler )

#直接用opener打开网页,如果服务器支持gzip/defalte则自动解压缩content = opener.open(url).read()

七、更方便地多线程

总结一文的确提及了一个简单的多线程模板,但是那个东东真正应用到程序里面去只会让程序变得支离破碎,不堪入目。在怎么更方便地进行多线程方面我也动了一番脑筋。先想想怎么进行多线程调用最方便呢?

1、用twisted进行异步I/O抓取

事实上更高效的抓取并非一定要用多线程,也可以使用异步I/O法:直接用twisted的getPage方法,然后分别加上异步I/O结束时的callback和errback方法即可。例如可以这么干:

from twisted.web.client import getPage

from twisted.internet import reactor

links = [ 'http://www.verycd.com/topics/%d/'%i for i in range(5420,5430) ]

def parse_page(data,url):

print len(data),url

def fetch_error(error,url):

print error.getErrorMessage(),url

# 批量抓取链接

for url in links:

getPage(url,timeout=5)

.addCallback(parse_page,url) #成功则调用parse_page方法.addErrback(fetch_error,url) #失败则调用fetch_error方法

reactor.callLater(5, reactor.stop) #5秒钟后通知reactor结束程序

reactor.run()

twisted人如其名,写的代码实在是太扭曲了,非正常人所能接受,虽然这个简单的例子看上去还好;每次写twisted的程序整个人都扭曲了,累得不得了,文档等于没有,必须得看源码才知道怎么整,唉不提了。

如果要支持gzip/deflate,甚至做一些登陆的扩展,就得为twisted写个新的HTTPClientFactory类诸如此类,我这眉头真是大皱,遂放弃。有毅力者请自行尝试。

这篇讲怎么用twisted来进行批量网址处理的文章不错,由浅入深,深入浅出,可以一看。

2、设计一个简单的多线程抓取类

还是觉得在urllib之类python“本土”的东东里面折腾起来更舒服。试想一下,如果有个Fetcher类,你可以这么调用

f = Fetcher(threads=10) #设定下载线程数为10

for url in urls:

f.push(url) #把所有url推入下载队列

while f.taskleft(): #若还有未完成下载的线程

content = f.pop() #从下载完成队列中取出结果

do_with(content) # 处理content内容

这么个多线程调用简单明了,那么就这么设计吧,首先要有两个队列,用Queue搞定,多线程的基本架构也和“技巧总结”一文类似,push方法和pop方法都比较好处理,都是直接用Queue的方法,taskleft则是如果有“正在运行的任务”或者”队列中的任务”则为是,也好办,于是代码如下:

import urllib2

from threading import Thread,Lock

from Queue import Queue

import time

class Fetcher:

def __init__(self,threads):

self.opener = urllib2.build_opener(urllib2.HTTPHandler)self.lock = Lock() #线程锁

self.q_req = Queue() #任务队列

self.q_ans = Queue() #完成队列

self.threads = threads

for i in range(threads):

t = Thread(target=self.threadget)

t.setDaemon(True)

t.start()

self.running = 0

def __del__(self): #解构时需等待两个队列完成

time.sleep(0.5)

self.q_req.join()

self.q_ans.join()

def taskleft(self):

return self.q_req.qsize()+self.q_ans.qsize()+self.runningdef push(self,req):

self.q_req.put(req)

def pop(self):

return self.q_ans.get()

def threadget(self):

while True:

req = self.q_req.get()

with self.lock: #要保证该操作的原子性,进入critical areaself.running += 1

try:

ans = self.opener.open(req).read()

except Exception, what:

ans = ''

print what

self.q_ans.put((req,ans))

with self.lock:

self.running -= 1

self.q_req.task_done()

time.sleep(0.1) # don't spam

if __name__ == "__main__":

links = [ 'http://www.verycd.com/topics/%d/'%i for i in range(5420,5430) ]

f = Fetcher(threads=10)

for url in links:

f.push(url)

while f.taskleft():

url,content = f.pop()

print url,len(content)

八、 一些琐碎的经验

1、连接池

opener.open和urllib2.urlopen一样,都会新建一个http请求。通常情况下这不是什么问题,因为线性环境下,一秒钟可能也就新生成一个请求;然而在多线程环境下,每秒钟可以是几十上百个请求,这么干只要几分钟,正常的有理智的服务器一定会封禁你的。

然而在正常的html请求时,保持同时和服务器几十个连接又是很正常的一件事,所以完全可以手动维护一个HttpConnection的池,然后每次抓取时从连接池里面选连接进行连接即可。

这里有一个取巧的方法,就是利用squid做代理服务器来进行抓取,则squid会自动为你维护连接池,还附带数据缓存功能,而且squid本来就是我每个服务器上面必装的东东,何必再自找麻烦写连接池呢。

2、设定线程的栈大小

栈大小的设定将非常显著地影响python的内存占用,python多线程不设置这个值会导致程序占用大量内存,这对openvz的vps来说非常致命。stack_size必须大于32768,实际上应该总要32768*2以上

from threading import stack_size

stack_size(32768*16)

3、设置失败后自动重试

def get(self,req,retries=3):

try:

response = self.opener.open(req)

data = response.read()

except Exception , what:

print what,req

if retries>0:

return self.get(req,retries-1)

else:

print 'GET Failed',req

return ''

return data

4、设置超时

import socket

socket.setdefaulttimeout(10) #设置10秒后连接超时

5、登陆

登陆更加简化了,首先build_opener中要加入cookie支持,参考“总结”一文;如要登陆VeryCD,给Fetcher新增一个空方法login,并在init()中调用,然后继承Fetcher类并override login方法:

def login(self,username,password):

import urllib

data=urllib.urlencode({'username':username,

'password':password,

'continue':'http://www.verycd.com/',

'login_submit':u'登录'.encode('utf-8'),

'save_cookie':1,})

url = 'http://www.verycd.com/signin'

self.opener.open(url,data).read()

于是在Fetcher初始化时便会自动登录VeryCD网站。

九、总结

如此,把上述所有小技巧都糅合起来就和我目前的私藏最终版的Fetcher类相差不远了,它支持多线程,gzip/deflate压缩,超时设置,自动重试,设置栈大小,自动登录等功能;代码简单,使用方便,性能也不俗,可谓居家旅行,杀人放火,咳咳,之必备工具。

之所以说和最终版差得不远,是因为最终版还有一个保留功能“马甲术”:多代理自动选择。看起来好像仅仅是一个random.choice的区别,其实包含了代理获取,代理验证,代理测速等诸多环节,这就是另一个故事了。

来自: observer

http://obmem.info/?p=476返回搜狐,查看更多

责任编辑:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python爬虫归纳_【知识归纳】史上最全的Python爬虫抓取技巧总结 的相关文章

  • linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析

    在驱动程序里 ioctl 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值 cmd除了可区别数字外 还包含有助于处理的几种相应信息 cmd的大小为 32位 共分 4 个域 bit31 bit30 2位为 区别读写 区
  • mybatis-plus-join用法

    mybatis plus join 使用方法 安装 maven
  • kafka源码之日志管理-LogManager

    LogManager 说明 LogManager实例的生成依赖于KafkaScheduler的后台调度管理组件 这个组件用于管理各partition的消息记录下index的信息 包含每个Partition的Log segment等的管理 实
  • linux查看端口号命令

    这本阿里P8撰写的算法笔记 再次推荐给大家 身边不少朋友学完这本书最后加入大厂 Github 疯传 史上最强悍 阿里大佬 LeetCode刷题手册 开放下载了 第一种 lsof i 端口号 第二种 netstat nltp grep 端口号
  • 基于SpringBoot+Thymeleaf仓库管理系统

    全网粉丝20W csdn特邀作者 博客专家 CSDN新星计划导师 java领域优质创作者 博客之星 掘金 华为云 阿里云 InfoQ等平台优质作者 专注于Java技术领域和毕业项目实战 文末获取项目下载方式 一 项目背景介绍 随着信息技术的
  • chrome Flash Player离线安装包下载

    Flash的离线安装包下载方式 适用于Chrome的Flash下载方式 https www flash cn flashplayer 3200101 install flash player ppapi cn exe 其中3200101代表
  • Angular UI-Router $ urlRouterProvider单击时不起作用

    如何解决Angular UI Router urlRouterProvider单击时不起作用 先前的解决方案 在0 2 12 我们可以使用的版本之前 urlRouterProvider when 在文档中建议使用 小引用 如何 设置默认 索
  • oracle connect by 学习

    Connect by 层次查询 https www bilibili com video BV1jV411t7CB share source copy web vd source d88a617727cccf1c106d623afec0c6
  • DBA 性能压测方法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 前言 压测的具体方法有很多种 工具也有很多 但是压测要遵循的原则可以是不变的 万变不离其宗 制定好压测规范和原则 每次压测前问下自己 为什么要进行压测 我们预期的结果是什么
  • log4js日志的使用与详解

    日志 log4js 1 安装与引入 npm install log4js var log4js require log4js 2 配置 log4js configure appenders fileout type file filenam
  • 区块链产品经理规范与总结

    产品顺序职责 产品顺序 产品助理 产品经理 高级产品经理 产品总监 产品专家 CEO 产品助理职责 辅助产品经理完成产品工作 包括调研 设计 开发 上线等项目阶段 配合产品经理 完成产品测试工作 驱动产品质量提升 产品研发前体验竞品 产品上
  • nodejs 读取xlsx文件内容

    文章目录 nodejs 读取xlsx文件内容 将excel的日期格式转成Date 对象 nodejs 读取xlsx文件内容 安装 npm i node xlsx D 注意 文件所在绝对路径 F jie baiyi tuberculosis
  • Vue 中 computed ,watch,methods 的异同

    methods watch和computed都是以函数为基础的 computed 和 watch 都可以观察页面的相应式数据的变化 当处理页面的数据变化时 我们有时候很容易滥用watch 而通常更好的办法是使用computed计算属性 而不
  • h5 video视频播放的同时加水印,图片加水印同样的原理

    经常能看到播放视频的网站上加水印的效果 记录下成果以备后续看 效果图如下 h5页面视频播放的同时加水印 有以下3种方法可尝试 在原视频上添加 由于每次登陆的用户不一样 需要根据用户名动态确定水印的文本值 这并不现实 捕捉视频的每一帧 重新画
  • Java集合面试题

    目录 1 Java中集合的框架图 2 常用集合的分类 3 List接口详解 3 1 ArrayList集合类 3 2 LinkedList集合类 3 3 Vector集合类 4 Map接口详解 4 1 HashMap集合类 4 2 Hash
  • MOS管规格书参数解析

    在这之前 首先了解下三极管和MOS管的区别 三极管是电流控制型的器件 通过基极电流去控制集电极电流 实现电流 电压信号放大或者驱动负载工作 场效应管是电压控制器件 需要通过栅极 G 电压来控制场效应的导通 实现场效应的导通和关断 三极管由两
  • html使用vue3.0必须使用element plus

    开发环境 html用的vue2 x版本配合elementui 现要求使用vue3 x版本 发现必须elementui只能适用vue2 x 故使用element plus 由于并非vue文件 现通过CDN方式导入
  • 【Visual C++】游戏开发笔记三十五 站在巨人的肩膀上 游戏引擎导论

    本系列文章由zhmxy555 毛星云 编写 转载请注明出处 文章链接 http blog csdn net zhmxy555 article details 8250057 作者 毛星云 浅墨 邮箱 happylifemxy 163 com
  • Redis总结

    Redis 1 NoSQL的引言 NoSQL Not Only SQL 意即不仅仅是SQL 泛指非关系型的数据库 Nosql这个技术门类 早期就有人提出 发展至2009年趋势越发高涨 2 为什么是NoSQL 随着互联网网站的兴起 传统的关系

随机推荐

  • 黑苹果睡眠无法唤醒(OC引导)

    NVRAM 随机访问存储器设置 UUID 7C436110 AB2A 4BBB A880 FE41995C9F82 键 boot args 添加值 igfxonln 1
  • 2018老男孩脱产班linux运维51期

    2018老男孩脱产班linux运维51期 2018老男孩脱产班linux运维51期 2018老男孩脱产班linux运维51期 2018老男孩脱产班linux运维51期 链接 https pan baidu com s 1bnIJF6IoBC
  • Linux网络配置实验

    Linux的网络配置分为两种 手动和自动 下面我们先配置好Linux外面的设置 后面再去终端用命令行配置 框起来的网址记住 后面要用上 这里开始打开终端 用命令行配置 这是手动配置的 将前面记下来的网址适当填入对应的位置 对照这种图稍作修改
  • PBFT(拜占庭容错)

    PBFT 拜占庭容错 基于拜占庭将军问题 一致性的确保主要分为这三个阶段 预准备 pre prepare 准备 prepare 和确认 commit 流程如下图所示 其中C为发送请求端 0123为服务端 3为宕机的服务端 具体步骤如下 1
  • MySQL数据库查询默认是按什么进行排序的

    文章中所有操作均是在 MySQL 5 7 版本下进行的 引入问题 MySQL 普通查询它是按照什么进行排序的 我们稍微讨论下这个问题 我们先引入一个测试表 drop table if exists tbl test create table
  • Swagger 整合 Spring Boot

    title Swagger 整合 Spring Boot date 2021 10 1 tags spring springboot swagger categories spring springboot Swagger 整合 Sprin
  • Relation-Aware Global Attention for Person Re-identification (cvpr2020)

    首先这是一篇科大和微软亚研院的文章 文章很优美 非常值得一阅 本文主要是针对行人重识别提出一种从局部之间的关系找到相关性从而生成注意力的方法 可以理解成继承 Non local 或者 self attention 的方法 虽然理念相似 这些
  • 【css】css3动画实现鼠标悬停按钮动画

    html a href span span Button a css body margin 0 padding 0 font family sans serif a position absolute top 50 left 50 tra
  • 【20201023期AI简报】OpenCV 4.5 发布、NVIDIA开源NeMo,更多精彩点我!

    导读 本期为 AI 简报 20201023 期 将为您带来过去一周关于 AI 新闻 12 条 其他互联网圈内新闻10 条 希望对您有所帮助 有更好的建议或者意见请在下方留言 AI 1 OpenCV 4 5 发布 DNN 模型在 ARM 平台
  • 数据库表的各种连接(内连接,外连接)

    关系型数据库 以关系代数为理论基础 1 用表 Table 表示关系或者实体 2 用行 Row 表示元组 3 用列 Col 表示属性 关系代数包含以下8个关系运算符 单表操作 1 选取 返回满足指定条件的行 2 投影 从数据集合中返回指定的列
  • Vue和React的优缺点

    Vue和React是目前最流行的前端框架之一 它们都有自己的优点和缺点 在这篇文章中 我将会详细介绍Vue和React的优缺点 并给出一些建议 帮助你选择适合自己的框架 一 Vue的优点 1 简单易学 Vue的语法简单易懂 学习曲线较为平缓
  • 关于U盘制作启动盘后内存变小问题的解决

    不需任何工具 只需要输入几个简单命令即可 1 U盘插入电脑然后运行windows的命令窗口 命令窗口打开方式win R后输入 cmd或点击开始菜单 gt gt 运行 gt gt 输入cmd 2 在命令行输入diskpart然后回车 如图所示
  • 爬虫爬取mp3文件例子

    相信训练模型时数据集的获取也是一个很头疼的事情 搞cv领域的可以扛着摄像头架起三脚架拍摄获取 以前干过 但是如果是nlp领域的呢 特别是chatgpt等大模型出来后对这类文本等数据的需求更大 如果没有现成的数据集的话基本上很难自己创造数据
  • vue自定义指令实现按钮鉴权

    vue中提供了创建自定义指令api directives 一般接口返回权限表如下 在路由守卫中用户登录情况下获取权限 并提交mutations存储在 vuex中 ajax获取菜单数据 let menuList permissions awa
  • vant+vue3+ts 的滑块验证

    vant vue3 ts 的滑块验证 效果图
  • SpringBoot可执行包结构

    相对于传统的JAVA可执行包 jar文件 SpringBoot的包结构有比较大的不一样 标准的JDK定义的jar文件里面是不能够有内嵌jar文件的 所以通常我们在执行一个jar文件里面的应用程序时 还需要通过 classpath来告诉JDK
  • Atcoder beginner contest 303

    A Similar String AC代码 include
  • 动物森友会【科大讯飞杯L题】【二分答案+最大流】

    题目链接 有N个物品 一周有7天 然后呢 要对应的每个物品都要达到各自的需求数量 于是问 最少需要几天才可以达到要求 很明显的 这是线性关系的 我们可以用二分答案来解决这个问题 然后呢怎么知道是否满足条件也就是来确定的 要满足每个物品都要拿
  • [Unity3D]第一人称角色控制器

    Unity3D 最简单最详细的第一人称角色控制器 自学Unity3D有一段时间了 一直想弄一个第一人称角色控制器 网上还是有很多教程和资料 但感觉有很多教程和资料理解起来比较复杂 在这里我结合网上所学的知识自己写了一个比较容易理解的Unit
  • python爬虫归纳_【知识归纳】史上最全的Python爬虫抓取技巧总结

    原标题 知识归纳 史上最全的Python爬虫抓取技巧总结 一 最基本的抓站 import urllib2 content urllib2 urlopen http XXXX read 二 使用代理服务器 这在某些情况下比较有用 比如IP被封