一、相对网址转绝对网址
项目需要爬取东方烟草网的要闻速递板块的新闻,使用Firebug检查发现,//tr[@id="titleList"]//td[@class="sj_text1"]/a/@href
中的网址是相对网址,无法直接访问,需要转成绝对网址才能进一步爬取该链接对应的内容。
在网上搜索发现很多相关介绍,出现频率最高的是urljoin_rfc函数,但我在我的pycharm中输这个函数会出现如下效果:
最后决定用urljoin函数把两段字符串形式的url拼接在一起。
又因为相对网址前面有../../
这种,所以使用.split()
函数切片取../后面的内容。
base_url_1 = 'http://www.eastobacco.com/zxbk/'
for i in range(0,len(item['temp_1'])):
temp = ''
relative_url = item['temp_1'][i].encode("utf-8")
temp = urljoin(base_url_1, relative_url.split('../')[-1])
但此时仍然会出现raiseValueError(‘Missing scheme in request url:%s’% self._url),再次检查发现,不同的相对地址的前缀还不一样,于是观察修改,分别给不同的相对地址添加上不同的前缀:
base_url_1 = 'http://www.eastobacco.com/zxbk/'
base_url_2 = 'http://www.eastobacco.com/zxbk/dyzxzx/ywsd/'
base_url_3 = 'http://www.eastobacco.com/zxbk/dyzxzx/'
base_url_4 = 'http://www.eastobacco.com/'
item['temp'] = []
j = 0
for i in range(0,len(item['temp_1'])):
temp = ''
relative_url = item['temp_1'][i].encode("utf-8")
if relative_url.startswith('../../gjjdzcybdj'): #gjjdzcybdj开头的,前面部分一直添加到zxbk
temp = urljoin(base_url_1, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if relative_url.startswith('./20'): #数字开头的,前面部分添加到ywsd
temp = urljoin(base_url_2, relative_url)
temp = temp.decode("utf-8")
if relative_url.startswith('../gjjwj/20'): #gjjwj开头的,前面部分添加到dyzxzx/
temp = urljoin(base_url_3, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if relative_url.startswith('../../../spyl'): # gjjdzcybdj开头的,前面部分一直添加到zxbk
temp = urljoin(base_url_4, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if (j % 2) == 0:
item['temp'].append(temp)
j = j + 1 # 每个标签里有两个重复的href
之所以要隔一个在item[‘temp’]里面append一个temp,是因为每个标题对应两个重复的href。
二、item中不同的key对应list的个数不同
放在东方烟草网这个例子中,就是说本来应该一个标题对应一个链接和一个日期的,但爬下来发现新闻标题数目和链接数目及日期数目不一致。
检查xpath后发现第一页的新闻标题中出现了一个生僻字:
这个搜狗输入法都打不出来的字(==)导致这一个标题对应了两个list元素
于是只好去重那个多出来的list元素。
三、爬下来的内容出现重复和遗漏
检查无误后运行爬虫,发现明明return的item中内容完整没有遗漏,但到了pipeline中的process_item
方法里,item中就出现了重复的内容,内容总数一定,所以就造成了一些内容的遗漏,百思不得其解,最后在settings.py
中加上
DOWNLOAD_DELAY = 3
DOWNLOAD_HANDLERS = {'s3': None}
减慢了爬虫速度后,内容终于正常。
四、完整代码及注释
test.py
# -*- coding: utf-8 -*-
#东方烟草网 要闻速递
__author__ = 'leilu'
import scrapy
from scrapy.spiders import Spider
from scrapy.selector import Selector
from testproject.items import TestprojectItem
from scrapy.http import Request
from scrapy.utils.response import get_base_url
from scrapy.utils.url import urljoin_rfc
from urlparse import urljoin
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
class DmozSpider(Spider):
name = "eastobacco"
start_urls = [
'http://www.eastobacco.com/zxbk/dyzxzx/ywsd/' #要闻速递
]
start_urls = []
for i in range(1, 5): #1-4
url = 'http://www.eastobacco.com/zxbk/dyzxzx/ywsd/index_' \
+ str(i) + '.html'
start_urls.append(url)
def parse(self, response):
sel = Selector(response) # Xpath选择器
item = TestprojectItem()
item['temp1'] = sel.xpath('//tr[@id="titleList"]//td[@class="sj_text1"]/a/text()').extract() #题目
item['temp_1'] = sel.xpath('//tr[@id="titleList"]//td[@class="sj_text1"]/a/@href').extract() #从start_urls中分析出的一个网址赋值给url
item['temp2'] = sel.xpath('//td[@class="sj_hui"]/text()').extract() #日期
#relative_url = sel.xpath('//td[@class="sj_text1"]/a/@href').extract()
base_url_1 = 'http://www.eastobacco.com/zxbk/'
base_url_2 = 'http://www.eastobacco.com/zxbk/dyzxzx/ywsd/'
base_url_3 = 'http://www.eastobacco.com/zxbk/dyzxzx/'
base_url_4 = 'http://www.eastobacco.com/'
item['temp'] = []
j = 0
for i in range(0,len(item['temp_1'])):
temp = ''
relative_url = item['temp_1'][i].encode("utf-8")
if relative_url.startswith('../../gjjdzcybdj'): #gjjdzcybdj开头的,前面部分一直添加到zxbk
temp = urljoin(base_url_1, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if relative_url.startswith('./20'): #数字开头的,前面部分添加到ywsd
temp = urljoin(base_url_2, relative_url)
temp = temp.decode("utf-8")
if relative_url.startswith('../gjjwj/20'): #gjjwj开头的,前面部分添加到dyzxzx/
temp = urljoin(base_url_3, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if relative_url.startswith('../../../spyl'): # gjjdzcybdj开头的,前面部分一直添加到zxbk
temp = urljoin(base_url_4, relative_url.split('../')[-1])
temp = temp.decode("utf-8")
if (j % 2) == 0:
item['temp'].append(temp)
j = j + 1 # 每个标签里有两个重复的href
#item['temp1'] = item['temp1'][:16]+item['temp1'][17:] #第一页的标题中有一个生僻字导致标题数量比链接和日期数多一个
print len(item['temp1'])
for url in item['temp']:
#print url
yield Request(url, meta={'item': item},
callback=self.parse_content)
def parse_content(self, response):
item = response.meta['item']
#print item['temp1']
num = item['temp'].index(response.url) #list.index(obj)返回找到对象的索引
item['title'] = item['temp1'][num]
#print item['title']
item['link'] = item['temp'][num] #即等于response.url
#print item['link']
item['date'] = item['temp2'][num]
#print item['date']
print '---第%s条---'%num
content1 = [
'//div[@class="TRS_Editor"]//p//text()',
]
for i in range(0, len(content1)):
if response.xpath(content1[i]).extract() != []:
item['content'] = response.xpath(content1[i]).extract()
break
else:
item['content'] = ['empty']
content = "" # 内容
for i in range(len(item['content'])):
content += item['content'][i]
content = "".join(content.split())
content = content.replace("'", "\"")
#print content
item['contentnew'] = []
item['contentnew'].append(content)
#print item['contentnew']
return item
pipeline.py可根据需要自己保存到数据库或Excel表,没什么难度,就不放了。