logo头像

一路过来,不过游牧自己。。

爬虫手记


最近写爬虫写的很开心,项目需求是要采集境外一些网站的关于PKK和巴基斯坦kill chinese people事件,途中也遇到很多问题,这篇博客主要是想记录一些问题,遇到的问题很多,也在慢慢找到感觉!我得去翻翻网页记录,一点点列出遇到的所有问题!

一、VPN问题

今天有遇到一些问题,就是在爬虫写完之后,当我开始执行的时候,会出现以下错误:

1
DEBUG: Retrying <GET https://www.voanews.com/s?k=Pakistan%2BChinese%2Bkidnapped> (failed 2 times): TCP connection timed out: 10060: 由于连接方在一段时间后没有正确答复或连接的主机没有 反应,连接尝试失败。.

这个错误显示的是什么呢,他最简单的提示就是没有链接到我所要爬取得页面,为什么会这样呢?我开了vpn,在找了一番错误之后,发现如果用天行开了PPTP模式之后,他显示的线路是可以访问网页观看视屏,但是是禁止下载BT和一些东西的,我想是这个原因,可是后来改成高速模式之后依然不行!心慌慌,跑去问大神,大神说可以试试换个VPN,用shadowsocks开启全局模式,在尝试了之后,发现竟然成功了,膜拜啊!

二、调试中的小错误

(1)这些错误都很小,但是为我整个过程积累了经验,所以我觉着有必要记录下来:

1
KeyError: ‘Spider not found: voa_scrapy.py’

这种错误典型的就是用scrapy crawl +爬虫名,这个爬虫名是程序中name后面定义的字符串,而不是简单的爬虫名,我的是name=’voa’,所以是crapy crawl voa
(2)windows下利用scrapy(python2.7)写爬虫,运行 scrapy crawl dmoz 命令时提示:exceptions.ImportError: No module named win32api
这没啥,主要是没安装pywin32,解决办法:安装pywin32
地址:!
(3)遇到错误:DEBUG: Crawled (403) <GET http://www.techbrood.com/> (referer: None)
表示网站采用了防爬技术anti-web-crawling technique(Amazon所用),比较简单即会检查用户代理(User Agent)信息。
解决方法:
在请求头部构造一个User Agent,如下所示:

1
2
def start_requests(self):        
yield Request("http://www.techbrood.com/", headers={'User-Agent': "your agent string"})

(4)Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
【解决过程】
1.对于此错误,最常见的原因是,的确没有对齐。但是我根据错误提示的行数,去代码中看了下,没啥问题啊。
都是用TAB键,对齐好了的,没有不对齐的行数啊。
2.以为是前面的注释的内容影响后面的语句的语法了,所以把前面的注释也删除了。
结果还是此语法错误。
3.后来折腾了半天,突然想到了,把当前python脚本的所有字符都显示出来看看有没有啥特殊的字符。

当前用的文本编辑器Notepad++,好像有个设置,可以显示所有的字符的。
找到了,在:
视图 -> 显示符号 -> 显示空格与制表符
这里可以看到tab键打出来的字符和空格打出来的字符是不一样的!那有什么方法是比较好取代的呢?去把对应的TAB,都改为空格,统一一下对齐的风格,即可。
在Notepad++中,去:
设置->首选项:语言->以空格取代(TAB键):
即可实现,对于以后每次的TAB输入,都自动转换为4个空格。

三、关于代理IP的获取和使用

有时候在爬取某个网站的时候,用同一个IP去访问网站,网站会认为这个是机器人,就会对这个ip进行一个ip限制,所以我们得用不同的ip去爬!那怎样去操作呢!

1、手动更新IP池

步骤如下:

(1)在settings配置文件中新增IP池:

1
2
3
4
5
6
7
8
9
IPPOOL=[  
{"ipaddr":"61.129.70.131:8080"},
{"ipaddr":"61.152.81.193:9100"},
{"ipaddr":"120.204.85.29:3128"},
{"ipaddr":"219.228.126.86:8123"},
{"ipaddr":"61.152.81.193:9100"},
{"ipaddr":"218.82.33.225:53853"},
{"ipaddr":"223.167.190.17:42789"}
]

这些IP可以从这个几个网站获取:快代理、代理66、有代理、西刺代理、guobanjia。如果出现像下面这种提示:”由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”或者是这种,” 由 于目标计算机积极拒绝,无法连接。”. 那就是IP的问题,更换就行了,这也有可能是我们上面说的原因!突然发现上面好多IP都不能用。如果需要,你可以自己去代理网站上去查!
在Scrapy中与代理服务器设置相关的下载中间件是HttpProxyMiddleware,对应的类为:

1
scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware

(2)修改中间件文件middlewares.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-  

# Define here the models for your spider middleware
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/spider-middleware.html

import random
from scrapy import signals
from myproxies.settings import IPPOOL

class MyproxiesSpiderMiddleware(object):

def __init__(self,ip=''):
self.ip=ip

def process_request(self, request, spider):
thisip=random.choice(IPPOOL)
print("this is ip:"+thisip["ipaddr"])
request.meta["proxy"]="http://"+thisip["ipaddr"]

这里就是将IPPOOL中的ip通过request传送出去!

(3)在settings中设置DOWNLOADER_MIDDLEWARES

1
2
3
4
5
DOWNLOADER_MIDDLEWARES = {  
# 'myproxies.middlewares.MyCustomDownloaderMiddleware': 543,
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':543,
'myproxies.middlewares.MyproxiesSpiderMiddleware':125
}

(4)爬虫文件为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- coding: utf-8 -*-  
import scrapy


class ProxieSpider(scrapy.Spider):


def __init__(self):
self.headers = {
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'Accept-Encoding':'gzip, deflate',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
}


name = "proxie"
allowed_domains = ["sina.com.cn"]
start_urls = ['http://news.sina.com.cn/']

def parse(self, response):
print(response.body)

(5)运行爬虫

1
scrapy crawl proxie

2、自动更新IP池

有时候可能随机的ip池中的ip还是不行,我们得写个程序去哪弄点ip过来!
(1)这里写个自动获取IP的类proxies.py,执行一下把获取的IP保存到txt文件中去:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# *-* coding:utf-8 *-*  
import requests
from bs4 import BeautifulSoup
import lxml
from multiprocessing import Process, Queue
import random
import json
import time
import requests

class Proxies(object):


"""docstring for Proxies"""
def __init__(self, page=3):
self.proxies = []
self.verify_pro = []
self.page = page
self.headers = {
'Accept': '*//*',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8'
}
self.get_proxies()
self.get_proxies_nn()

def get_proxies(self):
page = random.randint(1,10)
page_stop = page + self.page
while page < page_stop:
url = 'http://www.xicidaili.com/nt/%d' % page
html = requests.get(url, headers=self.headers).content
soup = BeautifulSoup(html, 'lxml')
ip_list = soup.find(id='ip_list')
for odd in ip_list.find_all(class_='odd'):
protocol = odd.find_all('td')[5].get_text().lower()+'://'
self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
page += 1

def get_proxies_nn(self):
page = random.randint(1,10)
page_stop = page + self.page
while page < page_stop:
url = 'http://www.xicidaili.com/nn/%d' % page
html = requests.get(url, headers=self.headers).content
soup = BeautifulSoup(html, 'lxml')
ip_list = soup.find(id='ip_list')
for odd in ip_list.find_all(class_='odd'):
protocol = odd.find_all('td')[5].get_text().lower() + '://'
self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
page += 1

def verify_proxies(self):
# 没验证的代理
old_queue = Queue()
# 验证后的代理
new_queue = Queue()
print ('verify proxy........')
works = []
for _ in range(15):
works.append(Process(target=self.verify_one_proxy, args=(old_queue,new_queue)))
for work in works:
work.start()
for proxy in self.proxies:
old_queue.put(proxy)
for work in works:
old_queue.put(0)
for work in works:
work.join()
self.proxies = []
while 1:
try:
self.proxies.append(new_queue.get(timeout=1))
except:
break
print ('verify_proxies done!')


def verify_one_proxy(self, old_queue, new_queue):
while 1:
proxy = old_queue.get()
if proxy == 0:break
protocol = 'https' if 'https' in proxy else 'http'
proxies = {protocol: proxy}
try:
if requests.get('http://www.baidu.com', proxies=proxies, timeout=2).status_code == 200:
print ('success %s' % proxy)
new_queue.put(proxy)
except:
print ('fail %s' % proxy)


if __name__ == '__main__':
a = Proxies()
a.verify_proxies()
print (a.proxies)
proxie = a.proxies
with open('proxies.txt', 'a') as f:
for proxy in proxie:
f.write(proxy+'\n')

执行一下: Python proxies.py 这些IP就会保存到proxies.txt文件中去

(2)修改代理文件middlewares.py的内容为如下:

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
import random  
import scrapy
from scrapy import log


# logger = logging.getLogger()

class ProxyMiddleWare(object):
"""docstring for ProxyMiddleWare"""
def process_request(self,request, spider):
'''对request对象加上proxy'''
proxy = self.get_random_proxy()
print("this is request ip:"+proxy)
request.meta['proxy'] = proxy


def process_response(self, request, response, spider):
'''对返回的response处理'''
# 如果返回的response状态不是200,重新生成当前request对象
if response.status != 200:
proxy = self.get_random_proxy()
print("this is response ip:"+proxy)
# 对当前reque加上代理
request.meta['proxy'] = proxy
return request
return response

def get_random_proxy(self):
'''随机从文件中读取proxy'''
while 1:
with open('G:\\Scrapy_work\\myproxies\\myproxies\\proxies.txt', 'r') as f:
proxies = f.readlines()
if proxies:
break
else:
time.sleep(1)
proxy = random.choice(proxies).strip()
return proxy

(3)修改下settings文件:

1
2
3
4
5
6
DOWNLOADER_MIDDLEWARES = {  
# 'myproxies.middlewares.MyCustomDownloaderMiddleware': 543,
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':None,
'myproxies.middlewares.ProxyMiddleWare':125,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware':None
}

(4)运行爬虫:

1
scrapy crawl proxie

这样就可以了!哈哈哈

多走路,多思考,越努力,越幸运!
———————————————YoungerFary

微信打赏

赞赏是不耍流氓的鼓励