pstuteville-scrubyt 0.4.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +355 -0
- data/COPYING +340 -0
- data/README.rdoc +121 -0
- data/Rakefile +120 -0
- data/VERSION +1 -0
- data/examples/README.txt +1 -0
- data/examples/events/delta/input.html +682 -0
- data/examples/events/delta/test.rb +16 -0
- data/examples/misc/auto_regex/input.html +22 -0
- data/examples/misc/auto_regex/test.rb +14 -0
- data/examples/misc/compound_example/advanced/test.rb +11 -0
- data/examples/misc/compound_example/advanced/tricky_compound.html +9 -0
- data/examples/misc/compound_example/regexp/regexp_compound.html +17 -0
- data/examples/misc/compound_example/regexp/test.rb +11 -0
- data/examples/misc/compound_example/simple/compound.html +5 -0
- data/examples/misc/compound_example/simple/test.rb +11 -0
- data/examples/misc/detail_page/detailpage.html +6 -0
- data/examples/misc/detail_page/index.html +9 -0
- data/examples/misc/detail_page/test.rb +17 -0
- data/examples/misc/google/test.rb +39 -0
- data/examples/misc/identical_examples/data_extractor_export.rb +12 -0
- data/examples/misc/identical_examples/input.html +16 -0
- data/examples/misc/identical_examples/test.rb +15 -0
- data/examples/misc/immediate_attribute_extraction/data_extractor_export.rb +10 -0
- data/examples/misc/immediate_attribute_extraction/input.html +16 -0
- data/examples/misc/immediate_attribute_extraction/test.rb +14 -0
- data/examples/misc/multiple_examples/input.html +7 -0
- data/examples/misc/multiple_examples/test.rb +22 -0
- data/examples/misc/on_click_next/next_page_link.rb +42 -0
- data/examples/misc/on_click_next/page_1.html +10 -0
- data/examples/misc/on_click_next/page_2.html +10 -0
- data/examples/misc/on_click_next/page_3.html +7 -0
- data/examples/misc/rubycorner/test.rb +29 -0
- data/examples/misc/rubyforge_login/test.rb +30 -0
- data/examples/misc/tables/ambigous_records/input.html +17 -0
- data/examples/misc/tables/ambigous_records/test.rb +37 -0
- data/examples/misc/tables/another_plain_table/input.html +15 -0
- data/examples/misc/tables/another_plain_table/test.rb +25 -0
- data/examples/misc/tables/complex_table/input.html +45 -0
- data/examples/misc/tables/complex_table/test.rb +30 -0
- data/examples/misc/tables/grab_rows/input.html +20 -0
- data/examples/misc/tables/grab_rows/test.rb +30 -0
- data/examples/misc/tables/plain_table/input.html +39 -0
- data/examples/misc/tables/plain_table/test.rb +35 -0
- data/examples/misc/tables/plain_table_morepages/2.html +38 -0
- data/examples/misc/tables/plain_table_morepages/3.html +33 -0
- data/examples/misc/tables/plain_table_morepages/input.html +40 -0
- data/examples/misc/tables/plain_table_morepages/test.rb +32 -0
- data/examples/misc/tables/plain_table_morepages_with_image/2.html +40 -0
- data/examples/misc/tables/plain_table_morepages_with_image/3.html +33 -0
- data/examples/misc/tables/plain_table_morepages_with_image/images/right_arrow.png +0 -0
- data/examples/misc/tables/plain_table_morepages_with_image/input.html +42 -0
- data/examples/misc/tables/plain_table_morepages_with_image/test.rb +32 -0
- data/examples/misc/tables/test_select_indices/input.html +46 -0
- data/examples/misc/tables/test_select_indices/test.rb +55 -0
- data/examples/misc/xpath_example_type/input.html +15 -0
- data/examples/misc/xpath_example_type/test.rb +18 -0
- data/examples/misc/yahoo_finance/test.rb +26 -0
- data/examples/social/blog_comment/test.rb +27 -0
- data/examples/social/del.icio.us/test.rb +22 -0
- data/examples/social/digg/test.rb +37 -0
- data/examples/social/dzone/test.rb +28 -0
- data/examples/social/linkedin/linkedin.rb +23 -0
- data/examples/social/reddit/test.rb +23 -0
- data/examples/tones_extractor_export.rb +23 -0
- data/examples/webshops/amazon/002-8212888-3924065.html +5311 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0130796034.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/020161622X.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0321223675.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0465067107.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0470069155.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0470081201.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0596005253.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0596101325.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0596523696.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0672328844.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0764596861.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0974514055.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0976694069.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0977616606.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0977616614.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/0977616630.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/1590597362.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/1594480060.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/1932394699.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/2841772101.jpg +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/amzn-logo-118w.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/askville-adwidget-bullet.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/askville-logo-sm-adwidget-white-bg.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/book_display_on_website-icon.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-inactive-no-ns.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-inactive-no.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-inactive-yes-ns.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-inactive-yes.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-no-tiny.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/btn-yes-tiny.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/buybox-button-find-gifts-a.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/c7y_badge_rn_1.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/cap-a9-3.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/drop-down-icon-small-arrow.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/endcap-a9-go-2.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/gb-open-new.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/gc-logo-popover-a.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/gift-cert-roto-pop-a.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/go-button-books.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/go-button.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/go-orange-trans.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/go_button_photo.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/logo-off.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/n2CoreLibs-events-18134.js +1407 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/n2CoreLibs-n2v1-57871.css +364 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/n2CoreLibs-simplePopover-41153.js +749 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/n2CoreLibs-utilities-25439.js +1608 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/orange-arrow.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/orange-arrow_002.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/popover-blurb.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/powered-by-a9.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/stars-3-5.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/stars-4-0.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/stars-4-5.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/stars-5-0.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/tagline-adwidget.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/topnav-cart.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/transparent-pixel.gif +0 -0
- data/examples/webshops/amazon/002-8212888-3924065_files/transparent-pixel_002.gif +0 -0
- data/examples/webshops/amazon/test.rb +27 -0
- data/examples/webshops/amazon-online/test.rb +34 -0
- data/examples/webshops/barnes_and_noble/test.rb +32 -0
- data/examples/webshops/barnes_offline/barnes_and_noble.html +115 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/10964080.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/10999676.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/11018492.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/11656534.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/11985045.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/12052378.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/12138286.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/12533212.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/12533268.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/9583392.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/SearchProduct.css +626 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin3_gtpointup.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_aboutshipping.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_account.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_colon.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_giftreminder.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_help.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_orderstatus.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/admin_wishlist.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/bg.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/btnGoGrn.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/cleardot.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/cleardot_002.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/dot4.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/dotGold20.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/hdCantFind.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/hdSearchResults.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/hgg_tab_home_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/hgg_tab_toy_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/iframeKMP.js +172 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2.html +25 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/070226_mc_lnav_search.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/XmlUtil.js +199 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/XslStyleSheet.js +1 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/kmp_gen.css +81 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/product-preview-core.js +337 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/product-preview.css +36 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/kmp_iframe_cds2_data/productpreview.js +11 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/linePagination.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/logo_bn05.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/navbar.js +34 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/navbar_06.css +136 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/popup_open.js +116 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/qsearch3_vline_dots.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/qsearch4_search.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/qsearch_AdvSearch.jpg +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/subnav_colon.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_Bookclubs_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_bnjr_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_books_hot.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_dvd_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_giftcards_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_home_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_member_cc_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_music_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_pipe.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_textbooksonly_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_usedoop_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/tab_videogames_cold.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/toppromo3_rule.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/toppromo_fastfree05.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/vcart_btn_checkout.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/vcart_icon_cart.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/vcart_topbot_rule.gif +0 -0
- data/examples/webshops/barnes_offline/barnes_and_noble_files/visualcart_prodid.js +401 -0
- data/examples/webshops/barnes_offline/test.rb +30 -0
- data/examples/webshops/buydig/2_files/03AA1BB9089A4A6A92CF23F280D664EB.jpg +0 -0
- data/examples/webshops/buydig/2_files/1008.gif +0 -0
- data/examples/webshops/buydig/2_files/1013.gif +0 -0
- data/examples/webshops/buydig/2_files/1020.gif +0 -0
- data/examples/webshops/buydig/2_files/106CF2FB84B446518397517C3E6D5AD8.jpg +0 -0
- data/examples/webshops/buydig/2_files/13-www.gif +0 -0
- data/examples/webshops/buydig/2_files/1E9BB2E56AB145FC9D6EF952703AF476.jpg +0 -0
- data/examples/webshops/buydig/2_files/1FCDFBE85CDB4D429EC2C8CB24D20457.jpg +0 -0
- data/examples/webshops/buydig/2_files/1pix.gif +0 -0
- data/examples/webshops/buydig/2_files/2014.gif +0 -0
- data/examples/webshops/buydig/2_files/2089.gif +0 -0
- data/examples/webshops/buydig/2_files/24992_medal.gif +0 -0
- data/examples/webshops/buydig/2_files/24BBCBA1397F4DDCBBBBE8456D6D6E5B.jpg +0 -0
- data/examples/webshops/buydig/2_files/281F8A6019B140F38DFD45EB7B69B0FB.jpg +0 -0
- data/examples/webshops/buydig/2_files/2975F866CB2149F7ACBC559C8E24E304.jpg +0 -0
- data/examples/webshops/buydig/2_files/316FC9256DC9460ABC3C5ECAF6C60286.jpg +0 -0
- data/examples/webshops/buydig/2_files/50569327D8B94252B95E449AE470E505.jpg +0 -0
- data/examples/webshops/buydig/2_files/519CDAB404FA4543B76B5F281468ACBF.jpg +0 -0
- data/examples/webshops/buydig/2_files/57D6146419A647BA89C96AF0B5CAB03C.jpg +0 -0
- data/examples/webshops/buydig/2_files/58E3F988E184448B8C0A59874AE123A8.jpg +0 -0
- data/examples/webshops/buydig/2_files/5E5B10197A4E4C9B9ECCD6309DBE4C54.jpg +0 -0
- data/examples/webshops/buydig/2_files/609A249177D04065B37B9161CB0BC92D.jpg +0 -0
- data/examples/webshops/buydig/2_files/676CEE8E53C2445982E991871B4DF613.jpg +0 -0
- data/examples/webshops/buydig/2_files/712BA08FAB524A31A76ABB9E2009FF8E.jpg +0 -0
- data/examples/webshops/buydig/2_files/734BD08D7A5049339393166491D09D21.jpg +0 -0
- data/examples/webshops/buydig/2_files/751E72B7003343248497FE6905F80787.jpg +0 -0
- data/examples/webshops/buydig/2_files/76493D4F02F14EF7B5886510604C7BB4.jpg +0 -0
- data/examples/webshops/buydig/2_files/79521E251278486DB29529C60C9D012A.jpg +0 -0
- data/examples/webshops/buydig/2_files/9C9AF82AC3B54BDC8C705278B50FDFD6.jpg +0 -0
- data/examples/webshops/buydig/2_files/BC3FD8307B9948FDB7EEF156D8629C37.jpg +0 -0
- data/examples/webshops/buydig/2_files/C0DD4574765047D1836F505E69DC8AE5.jpg +0 -0
- data/examples/webshops/buydig/2_files/C143F48515274A44B04F4B3E46306BD2.jpg +0 -0
- data/examples/webshops/buydig/2_files/C6B02E88F729464699DB275D140F4563.jpg +0 -0
- data/examples/webshops/buydig/2_files/CE334D6206DB4FA9AFDF339AEF0AF50F.jpg +0 -0
- data/examples/webshops/buydig/2_files/D66AE0DC865A4021AB300ED3A0C4CD11.jpg +0 -0
- data/examples/webshops/buydig/2_files/DEA2EC2093DC474D96B651068576DAE5.jpg +0 -0
- data/examples/webshops/buydig/2_files/F547677D83844042BF13A4BE6523BB50.jpg +0 -0
- data/examples/webshops/buydig/2_files/Rbbbonlineseal.gif +0 -0
- data/examples/webshops/buydig/2_files/TopSellers_bottom.gif +0 -0
- data/examples/webshops/buydig/2_files/TopSellers_ttl.gif +0 -0
- data/examples/webshops/buydig/2_files/addToFavorites_ttl.gif +0 -0
- data/examples/webshops/buydig/2_files/banner_CorporateSales.gif +0 -0
- data/examples/webshops/buydig/2_files/banner_Shipping.gif +0 -0
- data/examples/webshops/buydig/2_files/bizratehonoree.gif +0 -0
- data/examples/webshops/buydig/2_files/btn_submit.gif +0 -0
- data/examples/webshops/buydig/2_files/checkFlash.js +110 -0
- data/examples/webshops/buydig/2_files/checkFlash2.js +109 -0
- data/examples/webshops/buydig/2_files/cnetcertified.gif +0 -0
- data/examples/webshops/buydig/2_files/credPriceGrabber.gif +0 -0
- data/examples/webshops/buydig/2_files/credShopping.gif +0 -0
- data/examples/webshops/buydig/2_files/credential_paypal.gif +0 -0
- data/examples/webshops/buydig/2_files/credentials.gif +0 -0
- data/examples/webshops/buydig/2_files/dealtime.gif +0 -0
- data/examples/webshops/buydig/2_files/dvxstyle.css +754 -0
- data/examples/webshops/buydig/2_files/footer_021306_1_v1.gif +0 -0
- data/examples/webshops/buydig/2_files/func.js +132 -0
- data/examples/webshops/buydig/2_files/getseal +1 -0
- data/examples/webshops/buydig/2_files/help.gif +0 -0
- data/examples/webshops/buydig/2_files/home.gif +0 -0
- data/examples/webshops/buydig/2_files/java.js +155 -0
- data/examples/webshops/buydig/2_files/leftnv_help.gif +0 -0
- data/examples/webshops/buydig/2_files/logo.gif +0 -0
- data/examples/webshops/buydig/2_files/logo2.gif +0 -0
- data/examples/webshops/buydig/2_files/logo3.gif +0 -0
- data/examples/webshops/buydig/2_files/main.js +227 -0
- data/examples/webshops/buydig/2_files/mastercard_secured.gif +0 -0
- data/examples/webshops/buydig/2_files/newsBox_bkg.jpg +0 -0
- data/examples/webshops/buydig/2_files/newsBox_bottom.jpg +0 -0
- data/examples/webshops/buydig/2_files/newsBox_text.gif +0 -0
- data/examples/webshops/buydig/2_files/newsBox_ttl.jpg +0 -0
- data/examples/webshops/buydig/2_files/noimage75.gif +0 -0
- data/examples/webshops/buydig/2_files/orangeleftfrmbtm.gif +0 -0
- data/examples/webshops/buydig/2_files/pixel153.gif +0 -0
- data/examples/webshops/buydig/2_files/rightnv_bottom.gif +0 -0
- data/examples/webshops/buydig/2_files/search_btn_off.gif +0 -0
- data/examples/webshops/buydig/2_files/search_c1.gif +0 -0
- data/examples/webshops/buydig/2_files/search_c2.gif +0 -0
- data/examples/webshops/buydig/2_files/search_c3.gif +0 -0
- data/examples/webshops/buydig/2_files/search_c4.gif +0 -0
- data/examples/webshops/buydig/2_files/search_down.gif +0 -0
- data/examples/webshops/buydig/2_files/search_left.gif +0 -0
- data/examples/webshops/buydig/2_files/search_right.gif +0 -0
- data/examples/webshops/buydig/2_files/search_top.gif +0 -0
- data/examples/webshops/buydig/2_files/siteLinks_bottom.gif +0 -0
- data/examples/webshops/buydig/2_files/siteLinks_bullet.gif +0 -0
- data/examples/webshops/buydig/2_files/siteLinks_ttl.gif +0 -0
- data/examples/webshops/buydig/2_files/spacer.gif +0 -0
- data/examples/webshops/buydig/2_files/style.js +45 -0
- data/examples/webshops/buydig/2_files/styles.html +33 -0
- data/examples/webshops/buydig/2_files/track_orders.jpg +0 -0
- data/examples/webshops/buydig/2_files/urchin +534 -0
- data/examples/webshops/buydig/2_files/verified_by_visa.gif +0 -0
- data/examples/webshops/buydig/2_files/welcome.gif +0 -0
- data/examples/webshops/buydig/2_files/welcome_ttl.gif +0 -0
- data/examples/webshops/buydig/2_files/yahoologo.gif +0 -0
- data/examples/webshops/buydig/input.html +1194 -0
- data/examples/webshops/buydig/test.rb +31 -0
- data/examples/webshops/ebay/test.rb +32 -0
- data/examples/webshops/finewines_offline/_finewines.html +1739 -0
- data/examples/webshops/finewines_offline/_finewines_cut.html +371 -0
- data/examples/webshops/finewines_offline/_finewines_files/011064.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/012674.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/013268.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/013300.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/013409.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/014340.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/015073.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/015255.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/015479.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/015487.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017038.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017129.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017145.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017152.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017285.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017392.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/017400.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/019778.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/019786.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/020503.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/021253.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/021279.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/021337.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/021352.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/023002.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/023135.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/023143.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/023788.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/024166.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/024182.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/024216.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/027268.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/027516.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/027862.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/028118.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/028936.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033894.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033902.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033910.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033936.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033944.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/033951.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/034553.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/034561.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/232439.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/237834.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/268359.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/289082.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/331603.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/369686.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/420257.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/422014.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/460410.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/480533.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/556795.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/597054.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/650606.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/652628.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/653790.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/658450.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/660027.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/660951.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/684514.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/685131.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/686865.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/699330.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/703017.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/703140.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/703850.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/717306.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/900274.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/938225.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/947440.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/951319.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/967893.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/981407.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/981613.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/982421.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/985598.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/986737.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/987503.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/992800.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/VintageslogoEN.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/blanc-up.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/btn_vintages_latest.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/cc_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/common.js +860 -0
- data/examples/webshops/finewines_offline/_finewines_files/drink.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/drinkhold.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/ec_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/ev_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/hold.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/index-wines-features.jpg +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/indexSTYLE.css +398 -0
- data/examples/webshops/finewines_offline/_finewines_files/keyword_search.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/mm_menu.js +1 -0
- data/examples/webshops/finewines_offline/_finewines_files/nr_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/ontario_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/popup.js +81 -0
- data/examples/webshops/finewines_offline/_finewines_files/releases_nav.js +229 -0
- data/examples/webshops/finewines_offline/_finewines_files/so_en.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/spacer.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/top.gif +0 -0
- data/examples/webshops/finewines_offline/_finewines_files/urchin.js +576 -0
- data/examples/webshops/finewines_offline/_finewines_files/wom_en.gif +0 -0
- data/examples/webshops/finewines_offline/test.rb +30 -0
- data/examples/webshops/us1camera/1_files/1pix.gif +0 -0
- data/examples/webshops/us1camera/1_files/1pix_002.gif +0 -0
- data/examples/webshops/us1camera/1_files/CnetCertified.gif +0 -0
- data/examples/webshops/us1camera/1_files/CyberSource.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50_002.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50_003.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50_004.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50_005.gif +0 -0
- data/examples/webshops/us1camera/1_files/Images50_006.gif +0 -0
- data/examples/webshops/us1camera/1_files/PriceGrabber.gif +0 -0
- data/examples/webshops/us1camera/1_files/QSearch.gif +0 -0
- data/examples/webshops/us1camera/1_files/ban-m.jpg +0 -0
- data/examples/webshops/us1camera/1_files/banner1.bin +0 -0
- data/examples/webshops/us1camera/1_files/banner3.bin +0 -0
- data/examples/webshops/us1camera/1_files/block1.jpg +0 -0
- data/examples/webshops/us1camera/1_files/block2.jpg +0 -0
- data/examples/webshops/us1camera/1_files/block3.jpg +0 -0
- data/examples/webshops/us1camera/1_files/block4.jpg +0 -0
- data/examples/webshops/us1camera/1_files/block5.jpg +0 -0
- data/examples/webshops/us1camera/1_files/block6.jpg +0 -0
- data/examples/webshops/us1camera/1_files/bos.js +280 -0
- data/examples/webshops/us1camera/1_files/box1.jpg +0 -0
- data/examples/webshops/us1camera/1_files/box2.jpg +0 -0
- data/examples/webshops/us1camera/1_files/box3.jpg +0 -0
- data/examples/webshops/us1camera/1_files/box4.jpg +0 -0
- data/examples/webshops/us1camera/1_files/dot.jpg +0 -0
- data/examples/webshops/us1camera/1_files/eDevix.gif +0 -0
- data/examples/webshops/us1camera/1_files/electronics1.jpg +0 -0
- data/examples/webshops/us1camera/1_files/getseal +1 -0
- data/examples/webshops/us1camera/1_files/pride.jpg +0 -0
- data/examples/webshops/us1camera/1_files/search.jpg +0 -0
- data/examples/webshops/us1camera/1_files/sidebutton.jpg +0 -0
- data/examples/webshops/us1camera/1_files/sslroilogic.js +49 -0
- data/examples/webshops/us1camera/1_files/style.css +1 -0
- data/examples/webshops/us1camera/1_files/tl.html +2 -0
- data/examples/webshops/us1camera/input.html +548 -0
- data/examples/webshops/us1camera/test.rb +37 -0
- data/lib/scrubyt/core/navigation/agents/firewatir.rb +285 -0
- data/lib/scrubyt/core/navigation/agents/mechanize.rb +315 -0
- data/lib/scrubyt/core/navigation/fetch_action.rb +63 -0
- data/lib/scrubyt/core/navigation/navigation_actions.rb +107 -0
- data/lib/scrubyt/core/scraping/compound_example.rb +30 -0
- data/lib/scrubyt/core/scraping/constraint.rb +169 -0
- data/lib/scrubyt/core/scraping/constraint_adder.rb +49 -0
- data/lib/scrubyt/core/scraping/filters/attribute_filter.rb +14 -0
- data/lib/scrubyt/core/scraping/filters/base_filter.rb +112 -0
- data/lib/scrubyt/core/scraping/filters/constant_filter.rb +9 -0
- data/lib/scrubyt/core/scraping/filters/detail_page_filter.rb +37 -0
- data/lib/scrubyt/core/scraping/filters/download_filter.rb +64 -0
- data/lib/scrubyt/core/scraping/filters/html_subtree_filter.rb +9 -0
- data/lib/scrubyt/core/scraping/filters/regexp_filter.rb +13 -0
- data/lib/scrubyt/core/scraping/filters/script_filter.rb +11 -0
- data/lib/scrubyt/core/scraping/filters/text_filter.rb +34 -0
- data/lib/scrubyt/core/scraping/filters/tree_filter.rb +138 -0
- data/lib/scrubyt/core/scraping/pattern.rb +359 -0
- data/lib/scrubyt/core/scraping/pre_filter_document.rb +14 -0
- data/lib/scrubyt/core/scraping/result_indexer.rb +90 -0
- data/lib/scrubyt/core/shared/extractor.rb +171 -0
- data/lib/scrubyt/logging.rb +154 -0
- data/lib/scrubyt/output/post_processor.rb +139 -0
- data/lib/scrubyt/output/result.rb +44 -0
- data/lib/scrubyt/output/result_dumper.rb +154 -0
- data/lib/scrubyt/output/result_node.rb +145 -0
- data/lib/scrubyt/output/scrubyt_result.rb +42 -0
- data/lib/scrubyt/utils/compound_example_lookup.rb +50 -0
- data/lib/scrubyt/utils/ruby_extensions.rb +85 -0
- data/lib/scrubyt/utils/shared_utils.rb +58 -0
- data/lib/scrubyt/utils/simple_example_lookup.rb +40 -0
- data/lib/scrubyt/utils/xpathutils.rb +202 -0
- data/lib/scrubyt.rb +53 -0
- data/pkg/scrubyt-0.4.31.gem +0 -0
- data/resources/allison/LICENSE +184 -0
- data/resources/allison/README +37 -0
- data/resources/allison/allison.css +301 -0
- data/resources/allison/allison.gif +0 -0
- data/resources/allison/allison.js +307 -0
- data/resources/allison/allison.rb +287 -0
- data/resources/allison/cache/BODY +588 -0
- data/resources/allison/cache/CLASS_INDEX +4 -0
- data/resources/allison/cache/CLASS_PAGE +1 -0
- data/resources/allison/cache/FILE_INDEX +4 -0
- data/resources/allison/cache/FILE_PAGE +1 -0
- data/resources/allison/cache/FONTS +1 -0
- data/resources/allison/cache/FR_INDEX_BODY +1 -0
- data/resources/allison/cache/IMGPATH +1 -0
- data/resources/allison/cache/INDEX +1 -0
- data/resources/allison/cache/JAVASCRIPT +307 -0
- data/resources/allison/cache/METHOD_INDEX +4 -0
- data/resources/allison/cache/METHOD_LIST +1 -0
- data/resources/allison/cache/SRC_PAGE +1 -0
- data/resources/allison/cache/STYLE +323 -0
- data/resources/allison/cache/URL +1 -0
- data/scrubyt.gemspec +609 -0
- data/test/blackbox_test.rb +60 -0
- data/test/blackbox_tests/basic/multi_root.expected.xml +8 -0
- data/test/blackbox_tests/basic/multi_root.rb +6 -0
- data/test/blackbox_tests/basic/simple.expected.xml +5 -0
- data/test/blackbox_tests/basic/simple.rb +5 -0
- data/test/blackbox_tests/basic/three_divs.html +12 -0
- data/test/blackbox_tests/detail_page/detail_page_1.html +7 -0
- data/test/blackbox_tests/detail_page/detail_page_2.html +7 -0
- data/test/blackbox_tests/detail_page/main_page_1.html +5 -0
- data/test/blackbox_tests/detail_page/main_page_2.html +6 -0
- data/test/blackbox_tests/detail_page/one_detail_page.expected.xml +7 -0
- data/test/blackbox_tests/detail_page/one_detail_page.rb +9 -0
- data/test/blackbox_tests/detail_page/two_detail_pages.expected.xml +12 -0
- data/test/blackbox_tests/detail_page/two_detail_pages.rb +9 -0
- data/test/blackbox_tests/next_page/next_page_link.expected.xml +11 -0
- data/test/blackbox_tests/next_page/next_page_link.rb +7 -0
- data/test/blackbox_tests/next_page/page_1.html +11 -0
- data/test/blackbox_tests/next_page/page_2.html +11 -0
- data/test/blackbox_tests/next_page/page_3.html +7 -0
- data/test/blackbox_tests/next_page/page_list_links.expected.xml +11 -0
- data/test/blackbox_tests/next_page/page_list_links.rb +7 -0
- data/test/blackbox_tests/next_page/page_list_links.tofix +7 -0
- data/todo/backlog.txt +73 -0
- data/todo/scenario_ideas.txt +19 -0
- metadata +637 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
##
|
3
|
+
#=<tt>Describing actions which interact with the page</tt>
|
4
|
+
#
|
5
|
+
#This class contains all the actions that are used to navigate on web pages;
|
6
|
+
#first of all, *fetch* for downloading the pages - then various actions
|
7
|
+
#like filling textfields, submitting formst, clicking links and more
|
8
|
+
module NavigationActions
|
9
|
+
|
10
|
+
def self.extend_object(obj)
|
11
|
+
super(obj)
|
12
|
+
obj.instance_eval do
|
13
|
+
@current_form = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
#Action to fill a textfield with a query string
|
19
|
+
#
|
20
|
+
##*parameters*
|
21
|
+
#
|
22
|
+
#_textfield_name_ - the name of the textfield (e.g. the name of the google search
|
23
|
+
#textfield is 'q'
|
24
|
+
#
|
25
|
+
#_query_string_ - the string that should be entered into the textfield
|
26
|
+
def fill_textfield(textfield_name, query_string, use_value = nil)
|
27
|
+
FetchAction.fill_textfield(textfield_name, query_string, 0, use_value)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fill_textfield_and_wait(textfield_name, query_string, sleep_secs=0, use_value=nil)
|
31
|
+
FetchAction.fill_textfield(textfield_name, query_string, sleep_secs, use_value)
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
#Action to fill a textarea with text
|
36
|
+
def fill_textarea(textarea_name, text)
|
37
|
+
FetchAction.fill_textarea(textarea_name, text)
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
#Action for selecting an option from a dropdown box
|
42
|
+
def select_option(selectlist_name, option)
|
43
|
+
FetchAction.select_option(selectlist_name, option)
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_checkbox(checkbox_name)
|
47
|
+
FetchAction.check_checkbox(checkbox_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_radiobutton(checkbox_name, index=0)
|
51
|
+
FetchAction.check_radiobutton(checkbox_name, index=0)
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
#Fetch the document
|
56
|
+
def fetch(*args)
|
57
|
+
FetchAction.fetch(*args)
|
58
|
+
end
|
59
|
+
|
60
|
+
def use_current_page
|
61
|
+
FetchAction.use_current_page
|
62
|
+
end
|
63
|
+
##
|
64
|
+
#Submit the current form
|
65
|
+
def submit(index=nil, type=nil)
|
66
|
+
FetchAction.submit(index, nil, type)
|
67
|
+
end
|
68
|
+
|
69
|
+
def submit_and_wait(sleep_time, index=nil, type=nil)
|
70
|
+
FetchAction.submit(index, sleep_time, type)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
#Click the link specified by the text
|
75
|
+
def click_link(link_spec,index=0)
|
76
|
+
FetchAction.click_link(link_spec,index, 0)
|
77
|
+
end
|
78
|
+
|
79
|
+
def click_link_and_wait(link_spec, sleep_secs=0)
|
80
|
+
FetchAction.click_link(link_spec, 0, sleep_secs)
|
81
|
+
end
|
82
|
+
|
83
|
+
def click_by_xpath_if_exists(xpath, sleep_secs=0)
|
84
|
+
FetchAction.click_by_xpath_if_exists(xpath, sleep_secs)
|
85
|
+
end
|
86
|
+
|
87
|
+
def click_by_xpath(xpath)
|
88
|
+
FetchAction.click_by_xpath(xpath)
|
89
|
+
end
|
90
|
+
|
91
|
+
def click_by_xpath_and_wait(xpath, secs)
|
92
|
+
FetchAction.click_by_xpath(xpath, secs)
|
93
|
+
end
|
94
|
+
|
95
|
+
def click_image_map(index=0)
|
96
|
+
FetchAction.click_image_map(index)
|
97
|
+
end
|
98
|
+
|
99
|
+
def frame(attribute,value)
|
100
|
+
FetchAction.frame(attribute,value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def wait(time=1)
|
104
|
+
FetchAction.wait(time)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
##
|
3
|
+
#=<tt>Represents a compund example</tt>
|
4
|
+
#
|
5
|
+
#There are two types of string examples in scRUBYt! right now:
|
6
|
+
#the simple example and the compound example. The simple example
|
7
|
+
#is specified by a string, and a compound example is specified with
|
8
|
+
#:contains, :begins_with and :ends_with descriptors - which can be
|
9
|
+
#both regexps or strings
|
10
|
+
class CompoundExample
|
11
|
+
|
12
|
+
DESCRIPTORS = [:contains, :begins_with, :ends_with]
|
13
|
+
|
14
|
+
attr_accessor :descriptor_hash
|
15
|
+
|
16
|
+
def initialize(descriptor_hash)
|
17
|
+
@descriptor_hash = descriptor_hash
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
#Is the hash passed to this function a compound example descriptor hash?
|
22
|
+
#Need to decide this when parsing pattern parameters
|
23
|
+
def self.compound_example?(hash)
|
24
|
+
hash.each do |k,v|
|
25
|
+
return false if !DESCRIPTORS.include? k
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end# end of method
|
29
|
+
end# #end of class CompoundExample
|
30
|
+
end# end of module Scrubyt
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
##
|
3
|
+
#=<tt>Rejecting result instances based on further rules</tt>
|
4
|
+
#
|
5
|
+
#The two most trivial problems with a set of rules is that they match either less
|
6
|
+
#or more instances than we would like them to. Constraints are a way to remedy the second problem:
|
7
|
+
#they serve as a tool to filter out some result instances based on rules. A typical
|
8
|
+
#example:
|
9
|
+
#
|
10
|
+
#* *ensure_presence_of_ancestor_pattern* consider this model:
|
11
|
+
# <book>
|
12
|
+
# <author>...</author>
|
13
|
+
# <title>...</title>
|
14
|
+
# </book>
|
15
|
+
#
|
16
|
+
#If I attach the *ensure_presence_of_ancestor_pattern* to the pattern 'book' with values
|
17
|
+
#'author' and 'title', only those books will be matched which have an author and a
|
18
|
+
#title (i.e.the child patterns author and title must extract something). This is a way
|
19
|
+
#to say 'a book MUST have an author and a title'.
|
20
|
+
class Constraint
|
21
|
+
#There are more possible ways of applying/checking constraints in the case of
|
22
|
+
#ones that can not be checked in the context node (e.g. ensure_presence_of -
|
23
|
+
#since it may require the evaluation of child patterns of the context pattern to
|
24
|
+
#arbitray level)
|
25
|
+
#
|
26
|
+
#In such cases, the possibilities are:
|
27
|
+
#
|
28
|
+
#1) make a depth-first evaluation from the context pattern until the needed ancestor
|
29
|
+
# pattern is evaluated. This can mess things up, since if any ancestor node uses
|
30
|
+
# the sinks of predecessor(s) other than the context node, those need to be evaluated
|
31
|
+
# too, and we may run into a cyclyc dependency or at least a complicated recursion
|
32
|
+
#
|
33
|
+
#2) Post processing - evaluate normally and throw out results which do not pass the
|
34
|
+
# constraint
|
35
|
+
#
|
36
|
+
#2b) Do it on the XML level - most probably this solution will be implemented
|
37
|
+
|
38
|
+
# Different constraint types
|
39
|
+
CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_PATTERN = 0
|
40
|
+
CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ATTRIBUTE = 1
|
41
|
+
CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ATTRIBUTE = 2
|
42
|
+
CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ANCESTOR_NODE = 3
|
43
|
+
CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ANCESTOR_NODE = 4
|
44
|
+
|
45
|
+
|
46
|
+
attr_reader :type, :target
|
47
|
+
|
48
|
+
#Add 'ensure presence of ancestor pattern' constraint
|
49
|
+
|
50
|
+
#If this type of constraint is added to a pattern, it must have an ancestor pattern
|
51
|
+
#(child pattern, or child pattern of a child pattern, etc.) denoted by "ancestor"
|
52
|
+
#'Has an ancestor pattern' means that the ancestor pattern actually extracts something
|
53
|
+
#(just by looking at the wrapper model, the ancestor pattern is always present)
|
54
|
+
#Note that from this type of constraint there is no 'ensure_absence' version, since
|
55
|
+
#I could not think about an use case for that
|
56
|
+
def self.add_ensure_presence_of_pattern(ancestor)
|
57
|
+
Constraint.new(ancestor, CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_PATTERN)
|
58
|
+
end
|
59
|
+
|
60
|
+
#Add 'ensure absence of attribute' constraint
|
61
|
+
|
62
|
+
#If this type of constraint is added to a pattern, the HTML node it targets
|
63
|
+
#must NOT have an attribute named "attribute_name" with the value "attribute_value"
|
64
|
+
def self.add_ensure_absence_of_attribute(attribute_hash)
|
65
|
+
Constraint.new(attribute_hash,
|
66
|
+
CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ATTRIBUTE)
|
67
|
+
end
|
68
|
+
|
69
|
+
#Add 'ensure presence of attribute' constraint
|
70
|
+
|
71
|
+
#If this type of constraint is added to a pattern, the HTML node it targets
|
72
|
+
#must have an attribute named "attribute_name" with the value "attribute_value"
|
73
|
+
def self.add_ensure_presence_of_attribute(attribute_hash)
|
74
|
+
Constraint.new(attribute_hash,
|
75
|
+
CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ATTRIBUTE)
|
76
|
+
end
|
77
|
+
|
78
|
+
#Add 'ensure absence of ancestor node' constraint
|
79
|
+
|
80
|
+
#If this type of constraint is added to a pattern, the HTML node extracted by the pattern
|
81
|
+
#must NOT contain a HTML ancestor node called 'node_name' with the attribute set 'attributes'.
|
82
|
+
#
|
83
|
+
#"attributes" is an array of hashes, for example
|
84
|
+
#[{'font' => 'red'}, {'href' => 'http://www.google.com'}]
|
85
|
+
#in the case that more values have to be checked with the same key (e.g. 'class' => 'small' and '
|
86
|
+
#class' => 'wide' it has to be written as [{'class' => ['small','wide']}]
|
87
|
+
#
|
88
|
+
#"attributes" can be empty - in this case just the 'node_name' is checked
|
89
|
+
def self.add_ensure_absence_of_ancestor_node(node_name, attributes)
|
90
|
+
Constraint.new([node_name, attributes],
|
91
|
+
CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ANCESTOR_NODE)
|
92
|
+
end
|
93
|
+
|
94
|
+
#Add 'ensure presence of ancestor node' constraint
|
95
|
+
|
96
|
+
#If this type of constraint is added to a pattern, the HTML node extracted by the pattern
|
97
|
+
#must NOT contain a HTML ancestor node called 'node_name' with the attribute set 'attributes'.
|
98
|
+
#
|
99
|
+
#"attributes" is an array of hashes, for example
|
100
|
+
#[{'font' => 'red'}, {'href' => 'http://www.google.com'}]
|
101
|
+
#in the case that more values have to be checked with the same key (e.g. 'class' => 'small' and '
|
102
|
+
#class' => 'wide' it has to be written as [{'class' => ['small','wide']}]
|
103
|
+
#
|
104
|
+
#"attributes" can be empty - in this case just the 'node_name' is checked
|
105
|
+
def self.add_ensure_presence_of_ancestor_node(node_name, attributes)
|
106
|
+
Constraint.new([node_name, attributes],
|
107
|
+
CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ANCESTOR_NODE)
|
108
|
+
end
|
109
|
+
|
110
|
+
#Evaluate the constraint; if this function returns true,
|
111
|
+
#it means that the constraint passed, i.e. its filter will be added to the exctracted
|
112
|
+
#content of the pattern
|
113
|
+
def check(result)
|
114
|
+
case @type
|
115
|
+
#checked after evaluation, so here always return true
|
116
|
+
when CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_PATTERN
|
117
|
+
return true
|
118
|
+
when CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ATTRIBUTE
|
119
|
+
attribute_present(result)
|
120
|
+
when CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ATTRIBUTE
|
121
|
+
!attribute_present(result)
|
122
|
+
when CONSTRAINT_TYPE_ENSURE_PRESENCE_OF_ANCESTOR_NODE
|
123
|
+
ancestor_node_present(result)
|
124
|
+
when CONSTRAINT_TYPE_ENSURE_ABSENCE_OF_ANCESTOR_NODE
|
125
|
+
!ancestor_node_present(result)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
#We would not like these to be called from outside
|
131
|
+
def initialize(target, type)
|
132
|
+
@target = target
|
133
|
+
@type = type
|
134
|
+
end
|
135
|
+
|
136
|
+
#Implementation of the ancestor node presence test
|
137
|
+
#Check the documentation of the add_ensure_presence_of_ancestor_node method
|
138
|
+
#for further information on the result parameter
|
139
|
+
def ancestor_node_present(result)
|
140
|
+
found = false
|
141
|
+
node_name = @target[0]
|
142
|
+
node_attributes = @target[1]
|
143
|
+
node_attributes.each do |pair|
|
144
|
+
return true if !result.search("//#{node_name}[@#{pair[0]}='#{pair[1]}']").empty?
|
145
|
+
end
|
146
|
+
if node_attributes.empty?
|
147
|
+
return true if !result.search("//#{node_name}").empty?
|
148
|
+
end
|
149
|
+
false
|
150
|
+
end
|
151
|
+
|
152
|
+
def attribute_present(result)
|
153
|
+
return unless result.is_a? Hpricot::Elem
|
154
|
+
match = true
|
155
|
+
#If v = nil, the value of the attribute can be arbitrary;
|
156
|
+
#Therefore, in this case we just have to make sure that the attribute is
|
157
|
+
#present (i.e. != nil), we don't care about the value
|
158
|
+
@target.each do |k,v|
|
159
|
+
if v == nil
|
160
|
+
match &&= (result.attributes[k.to_s] != nil)
|
161
|
+
else
|
162
|
+
match &&= (result.attributes[k.to_s] == v.to_s)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
match
|
166
|
+
end
|
167
|
+
|
168
|
+
end #end of class
|
169
|
+
end #end of module
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
##
|
3
|
+
#=<tt>Utility class for adding constraints</tt>
|
4
|
+
#
|
5
|
+
#Originally methods of Pattern - but since Pattern was already too heavy (and after
|
6
|
+
#all, adding a constraint (logically) does not belong to Pattern anyway) it was moved
|
7
|
+
#to this utility class. In pattern everything that begins with ensure_
|
8
|
+
#is automatically dispatched here.
|
9
|
+
#
|
10
|
+
#I will not document the functions since these are just forwarders; See the 'real'
|
11
|
+
#functions with their documentation in Scrubyt::Constraint.rb
|
12
|
+
class ConstraintAdder
|
13
|
+
|
14
|
+
def self.ensure_presence_of_pattern(ancestor_node_name)
|
15
|
+
Constraint.add_ensure_presence_of_pattern(ancestor_node_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.ensure_presence_of_ancestor_node(ancestor_node_name, attributes=[])
|
19
|
+
Constraint.add_ensure_presence_of_ancestor_node(ancestor_node_name,
|
20
|
+
prepare_attributes(attributes))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.ensure_absence_of_ancestor_node(ancestor_node_name, attributes=[])
|
24
|
+
Constraint.add_ensure_absence_of_ancestor_node(ancestor_node_name,
|
25
|
+
prepare_attributes(attributes))
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.ensure_presence_of_attribute(attribute_hash)
|
29
|
+
Constraint.add_ensure_presence_of_attribute(attribute_hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.ensure_absence_of_attribute(attribute_hash)
|
33
|
+
Constraint.add_ensure_absence_of_attribute(attribute_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def self.prepare_attributes(attributes)
|
38
|
+
attribute_pairs = []
|
39
|
+
attributes.each do |key, value|
|
40
|
+
if (value.instance_of? Array)
|
41
|
+
value.each {|val| attribute_pairs << [key,val]}
|
42
|
+
else
|
43
|
+
attribute_pairs << [key, value]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return attribute_pairs
|
47
|
+
end #end of method prepare_attributes
|
48
|
+
end #end of class ConstraintAddere
|
49
|
+
end #end of module Scrubyt
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
class AttributeFilter < BaseFilter
|
3
|
+
|
4
|
+
def evaluate(source)
|
5
|
+
elem = XPathUtils.find_nearest_node_with_attribute(source, @example)
|
6
|
+
if elem.is_a? Hpricot::Elem
|
7
|
+
return [elem.attributes[@example]]
|
8
|
+
else
|
9
|
+
return nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end #End of class AttributeFilter
|
14
|
+
end #End of module Scrubyt
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
##
|
3
|
+
#=<tt>Filter out relevant pieces from the parent pattern</tt>
|
4
|
+
#
|
5
|
+
#A Scrubyt extractor is almost like a waterfall: water is pouring from the top until
|
6
|
+
#it reaches the bottom. The biggest difference is that instead of water, a HTML
|
7
|
+
#document travels through the space.
|
8
|
+
#
|
9
|
+
#Of course Scrubyt would not make much sense if the same document would arrive at
|
10
|
+
#the bottom that was poured in at the top - since in this case we might use an
|
11
|
+
#indentity transformation (i.e. do nothing with the input) as well.
|
12
|
+
#
|
13
|
+
#This is where filters came in: as they name says, they filter the stuff that is
|
14
|
+
#pouring from above, to leave the interesting parts and discard the rest.
|
15
|
+
#The working of a filter will be explained most easily by the help of an example.
|
16
|
+
#Let's consider that we would like to extract information from a webshop; Concretely
|
17
|
+
#we are interested in the name of the items and the URL pointing to the image of the
|
18
|
+
#item.
|
19
|
+
#
|
20
|
+
#To accomplish this, first we select the items with the pattern item (a pattern is
|
21
|
+
#a logical grouping of fillters; see Pattern documentation) Then our new
|
22
|
+
#context is the result extracted by the 'item' pattern; For every 'item' pattern, further
|
23
|
+
#extract the name and the image of the item; and finally, extract the href attribute
|
24
|
+
#of the image. Let's see an illustration:
|
25
|
+
#
|
26
|
+
# root --> This pattern is called a 'root pattern', It is invisible to you
|
27
|
+
# | and basically it represents the document; it has no filters
|
28
|
+
# +-- item --> Filter what's coming from above (the whole document) to get
|
29
|
+
# | relevant pieces of data (in this case webshop items)
|
30
|
+
# +-- name --> Again, filter what's coming from above (a webshop item) and
|
31
|
+
# | leave only item names after this operation
|
32
|
+
# +-- image --> This time filter the image of the item
|
33
|
+
# |
|
34
|
+
# +-- href --> And finally, from the image elements, get the attribute 'href'
|
35
|
+
class BaseFilter
|
36
|
+
#Type of the example this filter is extracted with
|
37
|
+
|
38
|
+
#XPath example, like html/body/tr/td[1] etc.
|
39
|
+
EXAMPLE_TYPE_XPATH = 0
|
40
|
+
#String from the document, for example 'Canon EOS 300 D'.
|
41
|
+
EXAMPLE_TYPE_STRING = 1
|
42
|
+
#Image example, like 'http://www.rubyrailways.com/scrubyt.jpg'
|
43
|
+
EXAMPLE_TYPE_IMAGE = 2
|
44
|
+
#No example - the actual XPath is determined from the children XPaths (their LCA)
|
45
|
+
EXAMPLE_TYPE_CHILDREN = 3
|
46
|
+
|
47
|
+
#Regexp example, like /\d+@*\d+[a-z]/
|
48
|
+
EXAMPLE_TYPE_REGEXP = 4
|
49
|
+
#Compound example, like :contains => 'goodies'
|
50
|
+
EXAMPLE_TYPE_COMPOUND = 5
|
51
|
+
|
52
|
+
attr_accessor(:example_type, :parent_pattern, :temp_sink,
|
53
|
+
:constraints, :xpath, :regexp, :example, :final_result)
|
54
|
+
|
55
|
+
def self.create(parent_pattern, example=nil)
|
56
|
+
filter_name = (parent_pattern.type.to_s.split("_").map!{|e| e.capitalize }.join) + 'Filter'
|
57
|
+
if filter_name == 'RootFilter'
|
58
|
+
BaseFilter.new(parent_pattern, example)
|
59
|
+
else
|
60
|
+
instance_eval("#{filter_name}.new(parent_pattern, example)")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#Dispatcher method to add constraints; of course, as with any method_missing, this method
|
65
|
+
#should not be called directly
|
66
|
+
|
67
|
+
#TODO still used?
|
68
|
+
alias_method :throw_method_missing, :method_missing
|
69
|
+
def method_missing(method_name, *args, &block)
|
70
|
+
case method_name.to_s
|
71
|
+
when /^ensure.+/
|
72
|
+
constraints << Constraint.send("add_#{method_name.to_s}".to_sym, self, *args)
|
73
|
+
else
|
74
|
+
throw_method_missing(method_name, *args, &block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
#We don't want this to be accessible from outside
|
80
|
+
def initialize(parent_pattern, example)
|
81
|
+
case parent_pattern.example_type
|
82
|
+
when :xpath
|
83
|
+
@example_type = EXAMPLE_TYPE_XPATH
|
84
|
+
else
|
85
|
+
@example_type = BaseFilter.determine_example_type(example)
|
86
|
+
end
|
87
|
+
@parent_pattern = parent_pattern
|
88
|
+
@example = example
|
89
|
+
@xpath = nil #The xpath to evaluate this filter
|
90
|
+
@constraints = [] #list of constraints
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.determine_example_type(example)
|
94
|
+
if example.instance_of? Regexp
|
95
|
+
EXAMPLE_TYPE_REGEXP
|
96
|
+
elsif example.instance_of? Hash
|
97
|
+
EXAMPLE_TYPE_COMPOUND
|
98
|
+
else
|
99
|
+
case example
|
100
|
+
when nil
|
101
|
+
EXAMPLE_TYPE_CHILDREN
|
102
|
+
when /\.(jpg|png|gif|jpeg)(\[\d+\])?$/
|
103
|
+
EXAMPLE_TYPE_IMAGE
|
104
|
+
when /^\/{1,2}[a-z]+[0-9]?(\[[0-9]+\])?(\/{1,2}[a-z()]+[0-9]?(\[[0-9]+\])?)*(\[@.+=.+\])?(\/@.+)?$/
|
105
|
+
(example.include? '/' || example.include?('[')) ? EXAMPLE_TYPE_XPATH : EXAMPLE_TYPE_STRING
|
106
|
+
else
|
107
|
+
EXAMPLE_TYPE_STRING
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end #end of method
|
111
|
+
end #End of class
|
112
|
+
end #End of module
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
class DetailPageFilter < BaseFilter
|
3
|
+
|
4
|
+
def evaluate(source)
|
5
|
+
if source.is_a?(String)
|
6
|
+
url = source
|
7
|
+
else
|
8
|
+
url = XPathUtils.find_nearest_node_with_attribute(source, 'href').attributes['href']
|
9
|
+
end
|
10
|
+
@parent_pattern.extractor.store_page
|
11
|
+
original_host_name = @parent_pattern.extractor.get_host_name
|
12
|
+
@parent_pattern.extractor.restore_host_name
|
13
|
+
|
14
|
+
begin
|
15
|
+
FetchAction.fetch url, :resolve => @parent_pattern.resolve
|
16
|
+
rescue
|
17
|
+
Scrubyt.log :ERROR, "Couldn't get page, probably returned 404 or 500 status code"
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
if @detail_extractor.nil?
|
22
|
+
@detail_extractor = Extractor.new @parent_pattern.extractor.mode, @parent_pattern.referenced_extractor
|
23
|
+
root_results = @detail_extractor.result
|
24
|
+
else
|
25
|
+
root_results = @detail_extractor.evaluate_extractor
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
@parent_pattern.extractor.restore_page
|
31
|
+
@parent_pattern.extractor.store_host_name original_host_name
|
32
|
+
|
33
|
+
root_results
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Scrubyt
|
5
|
+
class DownloadFilter < BaseFilter
|
6
|
+
|
7
|
+
def evaluate(source)
|
8
|
+
download_file(source)
|
9
|
+
end #end of method
|
10
|
+
|
11
|
+
private
|
12
|
+
def download_file(source)
|
13
|
+
return '' if source.size < 4
|
14
|
+
host_name = (source =~ /^http/ ? source : @parent_pattern.extractor.get_host_name)
|
15
|
+
outfile = nil
|
16
|
+
host_name += "/" if host_name[-1..-1] != "/"
|
17
|
+
base_url = host_name.scan(/http:\/\/(.+?)\//)[0][0]
|
18
|
+
file_name = source.scan(/.+\/(.*)/)[0][0]
|
19
|
+
return nil if @parent_pattern.except.include? file_name
|
20
|
+
Net::HTTP.start(base_url) { |http|
|
21
|
+
Scrubyt.log :INFO, "downloading: #{source.scan(/\s*(.+)/)[0][0]}"
|
22
|
+
begin
|
23
|
+
ua = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20061201 Firefox/2.0.0.4 (Ubuntu-feisty)'
|
24
|
+
path = host_name.scan(/http:\/\/#{base_url}(.+)\//)
|
25
|
+
resp = http.get(path, {'User-Agent'=> ua})
|
26
|
+
outfile = DownloadFilter.find_nonexisting_file_name(File.join(@example, file_name))
|
27
|
+
FileUtils.mkdir_p @example
|
28
|
+
open(outfile, 'wb') {|f| f.write(resp.body) }
|
29
|
+
rescue Timeout::Error
|
30
|
+
outfile = "[FAILED]#{file_name}"
|
31
|
+
end
|
32
|
+
}
|
33
|
+
outfile.scan(/.+\/(.*)/)[0][0]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find_nonexisting_file_name(file_name)
|
37
|
+
already_found = false
|
38
|
+
loop do
|
39
|
+
if File.exists? file_name
|
40
|
+
if already_found
|
41
|
+
if file_name.include?('.')
|
42
|
+
last_no = file_name.scan(/_(\d+)\./)[0][0]
|
43
|
+
file_name.sub!(/_#{last_no}\./) {"_#{(last_no.to_i+1).to_s}."}
|
44
|
+
else
|
45
|
+
last_no = file_name.scan(/_(\d+)$/)[0][0]
|
46
|
+
file_name.sub!(/_#{last_no}$/) {"_#{(last_no.to_i+1).to_s}"}
|
47
|
+
end
|
48
|
+
else
|
49
|
+
if file_name.include?('.')
|
50
|
+
file_name.sub!(/\./) {"_1\."}
|
51
|
+
already_found = true
|
52
|
+
else
|
53
|
+
file_name << '_1'
|
54
|
+
already_found = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
break
|
59
|
+
end
|
60
|
+
end
|
61
|
+
file_name
|
62
|
+
end #end of method
|
63
|
+
end #End of class DownloadFilter
|
64
|
+
end #End of module Scrubyt
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
class RegexpFilter < BaseFilter
|
3
|
+
|
4
|
+
def evaluate(source)
|
5
|
+
if source.is_a? String
|
6
|
+
source.scan(@example).flatten
|
7
|
+
else
|
8
|
+
source.inner_html.gsub(/<.*?>/, '').scan(@example).flatten
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end #End of class TreeFilter
|
13
|
+
end #End of module Scrubyt
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
class ScriptFilter < BaseFilter
|
3
|
+
|
4
|
+
def evaluate(source)
|
5
|
+
param = source
|
6
|
+
param = source.inner_html.gsub(/<.*?>/, "") unless source.is_a? String
|
7
|
+
@example.call param
|
8
|
+
end
|
9
|
+
|
10
|
+
end #End of class ConstantFilter
|
11
|
+
end #End of module Scrubyt
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Scrubyt
|
2
|
+
class TextFilter < BaseFilter
|
3
|
+
|
4
|
+
def evaluate(source)
|
5
|
+
return find_string(source) if @example =~ /^find\(/
|
6
|
+
final_element_name = @example.scan(/^(.+?)\[/)[0][0]
|
7
|
+
text = Regexp.escape(@example.scan(/\[(.+?)\]/)[0][0])
|
8
|
+
|
9
|
+
index = @example.scan(/\]:(.+)/).flatten
|
10
|
+
index = 0 if index.empty?
|
11
|
+
index = index[0].to_i unless index[0] == "all"
|
12
|
+
result = (index.is_a? Fixnum) ? (SharedUtils.traverse_for_match(source,/#{text}/)[index]) : (SharedUtils.traverse_for_match(source,/#{text}/))
|
13
|
+
return "" unless result
|
14
|
+
|
15
|
+
if index[0] == "all"
|
16
|
+
result.inject([]) {|a,r| a << XPathUtils.traverse_up_until_name(r,final_element_name); a}
|
17
|
+
else
|
18
|
+
[XPathUtils.traverse_up_until_name(result,final_element_name)]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_string(source)
|
23
|
+
str = @example.scan(/find\((.+)\)/).flatten[0]
|
24
|
+
strings_to_find = str.include?('|') ? str.split('|') : [str]
|
25
|
+
strings_to_find.each do |s|
|
26
|
+
result = SharedUtils.traverse_for_match(source,/#{s}/i)
|
27
|
+
return [s] unless result.empty?
|
28
|
+
end
|
29
|
+
return []
|
30
|
+
end
|
31
|
+
|
32
|
+
end #End of class TextFilter
|
33
|
+
end #End of module Scrubyt
|
34
|
+
|