【发布时间】:2016-08-31 22:44:13
【问题描述】:
我目前正在开发一个网络爬虫,它应该访问目录中的网站列表,访问网站的 CSS 样式表,检查 @media 标签(我知道这是检查响应式设计的基本方法还有其他极端情况需要考虑),并将所有不使用响应式设计的网站打印到文件中。
我相当肯定我实际检查 CSS 中是否有 @media 标签的方法工作正常,但是蜘蛛在确定是否找到带有 @media 标签的文件之前并没有访问所有 CSS 文件。我有一个测试文件,它在程序运行时记录调试输出,它显示了奇怪的模式,例如完成检查所有 CSS 文件,然后打印出它在文件中找到的内容,这是不应该发生的。
我希望有人可以查看我的代码并帮助我确定为什么这没有按照我想要的顺序发生。作为参考,目标是:
- 访问列表中的网站
- 访问该网站 HTML 头部元素中的每个 CSS 文件
- 如果找到@media 标签,我们就完成了,网站使用响应式设计
- 如果没有,请继续检查更多 CSS 文件
- 如果没有 CSS 文件包含 @media 标记,则该网站不使用响应式设计,应添加到列表中
这是我的代码(并非所有内容都能完美运行 - 例如,程序超时,因为我还没有使用 TimeOutError,但在大多数情况下,我觉得这应该可以正确评估网站,并且它没有这样做):
import scrapy
import re
import os.path
from scrapy.linkextractors import LinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from twisted.internet.error import TimeoutError
import time
class LCCISpider(CrawlSpider):
name = "lcci"
start_urls = ["http://www.lancasterchamber.com/busdirectory.aspx?mode=category"]
#Calls parse_item for every category link on main page
rules = (Rule(SgmlLinkExtractor(restrict_xpaths=('//div[@id="catListingResults"]/table/tr')),
callback = 'parse_item', follow = True),)
website_list = []
found_media = False
#Called for each category
def parse_item(self, response):
#For each site on the page, calls parse_website
sites = response.xpath('//div[@id="busListingResults"]/table/tr')
for site in sites:
urls = site.xpath('.//td/a[4]/@href').extract()
for url in urls:
if len(url) == 0:
continue
else:
new_site = response.urljoin(url)
yield scrapy.Request(new_site, callback=self.parse_website,
errback=self.errback_website)
def parse_website(self, response):
f = open('output2.txt', 'a')
f.write("NOW VISITING")
f.flush()
f.write(response.url)
f.flush()
f.write("\n")
f.flush()
f.close()
#reset found_media to false for each website
self.found_media = False
#for every link in the header, check potential css for @media tag
for href in response.css("head > link::attr('href')"):
url = response.urljoin(href.extract())
#if @media tag has not been found, continue checking css
if self.found_media == False:
#Call check_css for the url of the css file
yield scrapy.Request(url, callback=self.check_css,
errback=self.errback_website)
f = open('output2.txt', 'a')
f.write("step\n")
f.flush()
f.close()
else:
break
#if no @media tag is found in any link in the header, add the url to the website_list
if self.found_media == False:
#self.website_list.append(response.url)
f = open('output2.txt', 'a')
f.write("No @media tag in")
f.flush()
f.write(response.url)
f.flush()
f.write("\n")
f.flush()
f.close()
f = open('outputfalse2.txt', 'a')
f.write(response.url)
f.write("\n")
f.close()
else:
f = open('outputtrue.txt', 'a')
f.write(reponse.url)
f.write("\n")
f.close()
def check_css(self, response):
#Just a way of converting url into a string, the ".txt" is otherwise meaningless
string = str(response.url)
f = open('output2.txt', 'a')
f.write("Checking CSS in ")
f.write(response.url)
f.write("\n")
f.flush()
f.close()
#only perform regex search if it's a .css file
if (string[-4:] == ".css"):
media_match = re.search(r'@media', response.body, flags=0)
if media_match != None:
f = open('output2.txt', 'a')
f.write("found @media tag in " + response.url + "\n")
f.flush()
#If an @media tag is found, set found_media to True
self.found_media = True
f.close()
else:
f = open('output2.txt', 'a')
f.write("not css")
f.flush()
f.close()
def errback_website(self, failure):
if failure.check(TimeoutError):
request = failure.request
self.logger.error = ('TimeoutError on %s', request.url)
【问题讨论】:
-
我注意到的第一件事是您使用
self.found_media来控制蜘蛛状态。对于异步系统,您应该采取的方法是继续前进,直到找到一些东西,然后提高CloseSpider以结束。
标签: python css web scrapy web-crawler