Здесь скопированы десятка полтора фрагментов кода с примерами Scrapy LinkExtractor, Rules Больше двух правил в одном примере мне найти не удалось. Однако, надеюсь, что примеры регулярных выражений здесь на все случай паучьей жизни.
Link Extractors
Spiders
Recursively Scraping Web Pages With Scrapy - см ниже
Crawling a site recursively using scrapy - иногда рекурсия барахлит
Scrapy Crawler - How do I specify which links to crawl см.ниже
Парсинг сайтов с помощью фреймворка Scrapy - см ниже
postergully.com одно правило,
proyectounder.com - см. ниже... два правила, приемы для рег выражений, надо бы разобрать и скопировать себе
Scrapy: парсим только новые статьи
Do scrapy LinkExtractors end up with unique links?
Specifying rules in the Linkextractors in scrapy
How to create LinkExtractor rule which based on href in Scrapy
Showing results for import Link Extractor
Здесь устаревший SgmlLinkExtractor, но есть два правила Rule они работают по тем же принципам, что и сейчас
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.loader.processor import TakeFirst
from scrapy.contrib.loader import XPathItemLoader
from scrapy.selector import HtmlXPathSelector
from orphanage.items import OrphanageItem
class OrphanSpider(CrawlSpider):
name = "detskiedomiki"
allowed_domains = ["www.detskiedomiki.ru"]
start_urls = ["http://www.detskiedomiki.ru/guide/child/"]
rules = (
Rule(SgmlLinkExtractor(allow=('act=home_reg', 'act=home_zone')), follow=True),
Rule(SgmlLinkExtractor(allow=('act=home_more')), callback='parse_item'),
)
def parse_item(self, response):
...
rules - список правил обхода ресурса. В данном случае данный список содержит 2 правила - первое будет срабатывать при попадании паука на страницы, URL которых содержит act=home_reg или act=home_zone.
Под срабатыванием в данном случае подразумевается переход по ссылкам, извлеченным из этих страниц (за что отвечает аргумент follow=True).
Второе правило будет срабатывать при попадании паука на страницы, URL которых содержит act=home_more (именно на этих страницах содержится информация, которую мы хотим извлечь), например http://detskiedomiki.ru/?act=home_more&id=6278&z_id=3&part_id=65. В данном случае у правила не указан аргумент follow, что означает, что при попадании паука на данную страницу ссылки из неё не извлекаются, вместо этого содержимое страницы передаётся на вход функции, указанной в аргументе callback - назовём её в нашем случае parse_item.
Этих страниц на сайте уже нет, но сайт есть... здесь меня заинтересовали регулярные вражения (DATE_REGEX) и необычная структура модуля
# -*- coding: utf-8 -*-
from scrapy.xpath import HtmlXPathSelector
from scrapy.link.extractors import RegexLinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib_exp import adaptors
from eventscraper.items import EventscraperItem
from scrapy import log
from eventscraper import util
from string import join as j
from datetime import datetime, timedelta
import re
DATE_REGEX = re.compile(r'(\d+)\.(%s)\.(\d){,2}.*?([0-1]\d|2[0-4]):([0-5]\d)hs' % j([m[:3] for m in util.MONTHS], '|'), re.IGNORECASE)
def _fecha_adaptor(value):
m = DATE_REGEX.search(value)
if m is None:
raise Exception("Couldn't parse: %s" % value)
g = m.groups()
d = datetime(2000 + int(g[2]),
[m[:3] for m in util.MONTHS].index(g[1].lower()) + 1,
int(g[0]))
if int(g[3]) == 24: # 24 no es valido como hora, sumamos 1 dia a la fecha y seteamos hora a 0
d = d + timedelta(1)
d = datetime(d.year, d.month, d.day, 0, int(g[4]))
else:
d = datetime(d.year, d.month, d.day, int(g[3]), int(g[4]))
return d
class ProyectoUnderSpider(CrawlSpider):
domain_name = 'proyectounder.com'
start_urls = ['http://www.proyectounder.com/agenda.php?agenda=1']
rules = (
Rule(RegexLinkExtractor(allow=(r'/evento/\d+',)), 'parse_event', follow=True),
Rule(RegexLinkExtractor(allow=(r'/agenda.php\?action=display',)))
)
adaptor_pipe = [adaptors.extract, adaptors.delist(''), adaptors.strip]
adaptor_map = {
'summary': adaptor_pipe,
'description': adaptor_pipe,
'start_date': [adaptors.extract, adaptors.delist(''), _fecha_adaptor]
}
def parse_event(self, response):
i = EventscraperItem()
i.set_adaptors(self.adaptor_map)
xs = HtmlXPathSelector(response)
i.attribute('guid', response.url)
i.attribute('url', response.url)
i.attribute('summary', xs.x('//div[contains(@class, "eventoItem")]/h1/text()'))
i.attribute('description', xs.x('//div[contains(@class, "eventoItem")]/p/text()'))
i.attribute('start_date', xs.x('//div[contains(@class, "eventoItem")]/span[contains(@class, "fecha")][1]/text()'))
venue = {
'name': xs.x('//div[contains(@class, "agendaVermas")]//a[contains(@href, "agenda.php?lugar=")][1]/text()').extract()[0].strip(),
'city': xs.x('//div[contains(@class, "agendaVermas")]//a[contains(@href, "agenda.php?ciudad=")][1]/text()').extract()[0].strip()
}
log.msg(venue)
i.attribute('meta', {'source_site': 'proyectounder.com',
'scraped_on': datetime.now(),
'source_html': response.body })
return [i]
SPIDER = ProyectoUnderSpider()
Страница сайта рабочая http://sfbay.craigslist.org/npo/ В ссылке выше не только код, а подробный мануал, есть код на Гитхабе
In the first tutorial, I showed you how to write a crawler with Scrapy to scrape Craiglist Nonprofit jobs in San Francisco and store the data to a CSV file. This tutorial continues from where we left off, adding to the existing code, in order to build a recursive crawler to scrape multiple pages. Make sure you read the first tutorial first
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import HtmlXPathSelector
from craigslist_sample.items import CraigslistSampleItem
class MySpider(CrawlSpider):
name = "craigs"
allowed_domains = ["sfbay.craigslist.org"]
start_urls = ["http://sfbay.craigslist.org/npo/"]
rules = (Rule (SgmlLinkExtractor(allow=("index\d00\.html", ),restrict_xpaths=('//p[@class="nextpage"]',))
, callback="parse_items", follow= True),
)
def parse_items(self, response):
hxs = HtmlXPathSelector(response)
titles = hxs.select('//span[@class="pl"]')
items = []
for titles in titles:
item = CraigslistSampleItem()
item ["title"] = titles.select("a/text()").extract()
item ["link"] = titles.select("a/@href").extract()
items.append(item)
return(items)
Приме интересен тем, что в одном Rule и обратный вызов и следование по ссылке - По-видимому, это автор и называет рекурсией. Вот, как он описывает работу паука:
In essence, this spider started crawling at http://sfbay.craigslist.org/npo/ and then followed the “next 100 postings” link at the bottom, scraping the next page, until there where no more links to crawl.
Again, this can be used to create some powerful crawlers, so use with caution and set delays to throttle the crawling speed if necessary.
You have to create either two rules or one telling scrapy to allow the url of those types. Basically you want the rules list will be something like this
rules = (
Rule(SgmlLinkExtractor(allow=('http://www.cseblog.com/{d+}/{d+}/{*}.html', ), deny=( )),call_back ='parse_save' ),
Rule(SgmlLinkExtractor(allow=('http://www.cseblog.com/search/{*}', ), deny=( )),,call_back = 'parse_only' ))
А вот первоначальный код, сайт рабочий. Используется BeautifulSoup для парсинга.
from scrapy.spider import BaseSpider
from bs4 import BeautifulSoup ## This is BeautifulSoup4
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from blogscraper.items import BlogArticle ## This is for saving data. Probably insignificant.
class BlogArticleSpider(BaseSpider):
name = "blogscraper"
allowed_domains = ["cseblog.com"]
start_urls = [
"http://www.cseblog.com/",
]
rules = (
Rule(SgmlLinkExtractor(allow=('\d+/\d+/*"', ), deny=( ))),
)
def parse(self, response):
site = BeautifulSoup(response.body_as_unicode())
items = []
item = BlogArticle()
item['title'] = site.find("h3" , {"class": "post-title" } ).text.strip()
item['link'] = site.find("h3" , {"class": "post-title" } ).a.attrs['href']
item['text'] = site.find("div" , {"class": "post-body" } )
items.append(item)
return items
Из этого блога я скопирова код из двух постов... Что это за scrapylib не знал
scrapy crawl scrapy_test -o file.csv -t csv
#код scrapy_test:
#! coding: utf-8
__author__ = 'acman'
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.item import Item, Field
#
#
class ScrapyTestItem(Item):
title = Field()
category = Field()
url = Field()
text = Field()
#
#
class ScrapyTestSpider(CrawlSpider):
name = "scrapy_test"
allowed_domains = ["www.acman.ru"]
start_urls = ["http://www.acman.ru/blog/"]
#
rules = (
Rule(LinkExtractor(allow=(r'/blog/\d+')),
callback='parse_item', follow=True),
)
#
def parse_item(self, response):
self.log('%s' % response.url)
item = ScrapyTestItem()
item['title'] = response.xpath('//h2[@class]/a/text()').extract()
item['category'] = response.xpath('//h3/a/text()').extract()
item['text'] = response.xpath(
'//div[@class="entry"]//p | //pre/code').extract()
item['url'] = response.url
return item
#Одни и те же материалы нет смысла каждый раз записывать, будем добавлять в таблицу только новые.
#Все остается по старому как в предыдущей статье Scrapy: парсер блога ,
#запускаем паука тоже так же, добавим только middleware DeltaFetch из пакета scrapylib
#Установим:
pip install scrapylib
#Добавим в settings.py
SPIDER_MIDDLEWARES = {
'scrapylib.deltafetch.DeltaFetch': 100,
}
DELTAFETCH_ENABLED = True
#Все готово!
Обратил внимание на regex \/.+.
rules = [
Rule(LinkExtractor(allow='page=\d+')),
Rule(LinkExtractor(allow=['article\/.+\.html']), callback='parse_article')
]
*Пример со start_requests*
from scrapy.http.request import Request
def start_requests(self):
for i in xrange(1, 100):
url = 'www.examples.com/sports/companies?searchTerm=news+sports&pg=' + i
yield Request(url=url, callback=parse_torrent)
Следует разобрать пример с re.compile(r'^http://example.com/category/\?.?(?=page=\d+)')*
Rule(LinkExtractor(allow=('^http://example.com/category/\?.*?(?=page=\d+)', )), callback='parse_item'),
#Demo (using your example urls):
>>> import re
>>> pattern = re.compile(r'^http://example.com/category/\?.*?(?=page=\d+)')
>>> should_match = [
... 'http://example.com/category/?sort=a-z&page=1',
... 'http://example.com/category/?page=1&sort=a-z&cache=1',
... 'http://example.com/category/?page=1&sort=a-z#'
... ]
>>> for url in should_match:
... print "Matches" if pattern.search(url) else "Doesn't match"
Посты чуть ниже также могут вас заинтересовать
спасибо за хорошую подборку примеров с LinkExtractor!!
ОтветитьУдалитьКлассная подборка, спасибо!
ОтветитьУдалитьКлассная подборка, спасибо!
ОтветитьУдалить