selen với liệu pháp cho trang động


85

Tôi đang cố gắng thu thập thông tin sản phẩm từ một trang web bằng cách sử dụng phương pháp thu thập dữ liệu. Trang web sắp sửa của tôi trông như thế này:

  • bắt đầu với trang product_list với 10 sản phẩm
  • một cú nhấp chuột vào nút "tiếp theo" sẽ tải 10 sản phẩm tiếp theo (url không thay đổi giữa hai trang)
  • tôi sử dụng LinkExtractor để theo từng liên kết sản phẩm vào trang sản phẩm và nhận được tất cả thông tin tôi cần

Tôi đã cố gắng tái tạo lệnh gọi tiếp theo nhưng không thể hoạt động, vì vậy, tôi đang dùng thử selen. Tôi có thể chạy webdriver của selen trong một tập lệnh riêng biệt, nhưng tôi không biết cách tích hợp với scrapy. Tôi sẽ đặt phần selen ở đâu trong con nhện phế liệu của mình?

Con nhện của tôi khá chuẩn, như sau:

class ProductSpider(CrawlSpider):
    name = "product_spider"
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/shanghai']
    rules = [
        Rule(SgmlLinkExtractor(restrict_xpaths='//div[@id="productList"]//dl[@class="t2"]//dt'), callback='parse_product'),
        ]

    def parse_product(self, response):
        self.log("parsing product %s" %response.url, level=INFO)
        hxs = HtmlXPathSelector(response)
        # actual data follows

Bất kỳ ý tưởng được đánh giá cao. Cảm ơn bạn!


Câu trả lời:


122

Nó thực sự phụ thuộc vào cách bạn cần quét trang web và cách thức và dữ liệu bạn muốn lấy.

Đây là một ví dụ về cách bạn có thể theo dõi phân trang trên ebay bằng cách sử dụng Scrapy+ Selenium:

import scrapy
from selenium import webdriver

class ProductSpider(scrapy.Spider):
    name = "product_spider"
    allowed_domains = ['ebay.com']
    start_urls = ['http://www.ebay.com/sch/i.html?_odkw=books&_osacat=0&_trksid=p2045573.m570.l1313.TR0.TRC0.Xpython&_nkw=python&_sacat=0&_from=R40']

    def __init__(self):
        self.driver = webdriver.Firefox()

    def parse(self, response):
        self.driver.get(response.url)

        while True:
            next = self.driver.find_element_by_xpath('//td[@class="pagn-next"]/a')

            try:
                next.click()

                # get the data and write it to scrapy items
            except:
                break

        self.driver.close()

Dưới đây là một số ví dụ về "nhện selen":


Ngoài ra còn có một giải pháp thay thế để phải sử dụng Seleniumvới Scrapy. Trong một số trường hợp, sử dụng ScrapyJSphần mềm trung gian là đủ để xử lý các phần động của trang. Mẫu sử dụng trong thế giới thực:


Cảm ơn bạn đã giúp đỡ. Thực ra vấn đề lớn nhất của tôi là ở phần sau next.click (). Mỗi khi tôi nhận được một trang mới, nhưng tôi vẫn có thể sử dụng LinkExtractor để trích xuất tất cả các url của sản phẩm rồi sử dụng lệnh gọi lại để phân tích cú pháp chúng?
Z. Lin

2
Có cách nào để sử dụng lại phản hồi đã bị thu hồi thay vì sử dụng self.driver.get(response.url)không?
khiết

2
@HalcyonAbrahamRamirez đây chỉ là một ví dụ với phần selen trong nhện phế liệu. Sau khi thực hiện xong selen, thông thường giá trị self.driver.page_sourcesẽ được chuyển đến một thể hiện Selector để Scrapy phân tích cú pháp HTML, tạo các thể hiện mục, chuyển chúng đến đường ống, v.v. Hoặc, cookie selen có thể được phân tích cú pháp và chuyển đến Scrapy để thực hiện các yêu cầu bổ sung. Nhưng, nếu bạn không cần sức mạnh của kiến ​​trúc khung trị liệu, thì chắc chắn, bạn có thể chỉ sử dụng selen - bản thân nó khá mạnh trong việc định vị các phần tử.
alecxe

4
@alecxe vâng trong khi tôi có khái niệm. Tôi vẫn còn bối rối ở phần mà bạn trích xuất nguồn trang bằng cách sử dụng selen và chuyển các phần tử bạn muốn được cạo để xử lý. ví dụ. Có một nút tải nhiều hơn nhấp vào nó sẽ hiển thị nhiều mục hơn nhưng bạn trích xuất đường dẫn xpath cho các mục đó. bây giờ làm thế nào để bạn chuyển những xpaths đó đến liệu pháp? bởi vì chỉ có các mục được hiển thị khi bạn lần đầu tiên yêu cầu trang web sẽ được phân tích bởi khá rắn và không phải là những sau khi nhấp vào nút tải hơn với selen
Halcyon Abraham Ramirez

2
@HalcyonAbrahamRamirez đã hiểu, tôi sẽ tải thêm các mục khác cho đến khi không còn hàng nào để thêm. Sau đó, đi driver.page_sourcevà vượt qua nó để Selector()..
alecxe

2

Nếu (url không thay đổi giữa hai trang) thì bạn nên thêm dont_filter = True với scrapy của mình. Request () hoặc scrapy sẽ tìm url này là một bản sao sau khi xử lý trang đầu tiên.

Nếu bạn cần hiển thị các trang bằng javascript, bạn nên sử dụng scrapy-splash , bạn cũng có thể kiểm tra phần mềm trung gian scrapy này có thể xử lý các trang javascript bằng cách sử dụng selen hoặc bạn có thể làm điều đó bằng cách khởi chạy bất kỳ trình duyệt không có đầu nào

Nhưng giải pháp hiệu quả hơn và nhanh hơn là kiểm tra trình duyệt của bạn và xem những yêu cầu nào được thực hiện trong quá trình gửi biểu mẫu hoặc kích hoạt một sự kiện nhất định. Cố gắng mô phỏng các yêu cầu giống như trình duyệt của bạn gửi. Nếu bạn có thể sao chép (các) yêu cầu một cách chính xác, bạn sẽ nhận được dữ liệu mình cần.

Đây là một ví dụ :

class ScrollScraper(Spider):
    name = "scrollingscraper"

    quote_url = "http://quotes.toscrape.com/api/quotes?page="
    start_urls = [quote_url + "1"]

    def parse(self, response):
        quote_item = QuoteItem()
        print response.body
        data = json.loads(response.body)
        for item in data.get('quotes', []):
            quote_item["author"] = item.get('author', {}).get('name')
            quote_item['quote'] = item.get('text')
            quote_item['tags'] = item.get('tags')
            yield quote_item

        if data['has_next']:
            next_page = data['page'] + 1
            yield Request(self.quote_url + str(next_page))

Khi url phân trang giống nhau cho mọi trang và sử dụng yêu cầu POST thì bạn có thể sử dụng scrapy.FormRequest () thay vì scrapy.Request () , cả hai đều giống nhau nhưng FormRequest thêm một đối số mới ( formdata = ) vào hàm tạo.

Đây là một ví dụ về nhện khác trong bài đăng này :

class SpiderClass(scrapy.Spider):
    # spider name and all
    name = 'ajax'
    page_incr = 1
    start_urls = ['http://www.pcguia.pt/category/reviews/#paginated=1']
    pagination_url = 'http://www.pcguia.pt/wp-content/themes/flavor/functions/ajax.php'

    def parse(self, response):

        sel = Selector(response)

        if self.page_incr > 1:
            json_data = json.loads(response.body)
            sel = Selector(text=json_data.get('content', ''))

        # your code here

        # pagination code starts here
        if sel.xpath('//div[@class="panel-wrapper"]'):
            self.page_incr += 1
            formdata = {
                'sorter': 'recent',
                'location': 'main loop',
                'loop': 'main loop',
                'action': 'sort',
                'view': 'grid',
                'columns': '3',
                'paginated': str(self.page_incr),
                'currentquery[category_name]': 'reviews'
            }
            yield FormRequest(url=self.pagination_url, formdata=formdata, callback=self.parse)
        else:
            return
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.