[pornpics] add 'category' and 'listing' extractors (#8662)

* [pornpics] add category and listing extractors

Add support for:
- Category pages like /ass/, /milf/, /blonde/ etc.
- Listing pages like /popular/, /recent/, /rating/, /likes/, /views/, /comments/

Category pages use JSON pagination like tags/search.
Listing pages don't support JSON pagination and use different HTML structure.

* [pornpics] simplify category pattern via class ordering

- Move PornpicsCategoryExtractor after PornpicsListingExtractor
  so it acts as catch-all, eliminating need for negative lookahead
- Use list comprehension in PornpicsListingExtractor.galleries()

* update docs/supportedsites
This commit is contained in:
SpiffyChatterbox
2025-12-10 14:00:07 -05:00
committed by GitHub
parent f5fafd7977
commit 2c8250919b
3 changed files with 75 additions and 1 deletions

View File

@@ -856,7 +856,7 @@ Consider all listed sites to potentially be NSFW.
<tr id="pornpics" title="pornpics">
<td>PornPics.com</td>
<td>https://www.pornpics.com/</td>
<td>Galleries, Search Results, Tag Searches</td>
<td>Categories, Galleries, Listings, Search Results, Tag Searches</td>
<td></td>
</tr>
<tr id="pornstarstube" title="pornstarstube">

View File

@@ -116,3 +116,35 @@ class PornpicsSearchExtractor(PornpicsExtractor):
"offset": 0,
}
return self._pagination(url, params)
class PornpicsListingExtractor(PornpicsExtractor):
"""Extractor for galleries from pornpics listing pages
These pages (popular, recent, etc.) don't support JSON pagination
and use single quotes in HTML, unlike category pages.
"""
subcategory = "listing"
pattern = (rf"{BASE_PATTERN}"
rf"/(popular|recent|rating|likes|views|comments)/?$")
example = "https://www.pornpics.com/popular/"
def galleries(self):
url = f"{self.root}/{self.groups[0]}/"
page = self.request(url).text
return [
{"g_url": href}
for href in text.extract_iter(
page, "class='rel-link' href='", "'")
]
class PornpicsCategoryExtractor(PornpicsExtractor):
"""Extractor for galleries from pornpics categories"""
subcategory = "category"
pattern = rf"{BASE_PATTERN}/([^/?#]+)/?$"
example = "https://www.pornpics.com/ass/"
def galleries(self):
url = f"{self.root}/{self.groups[0]}/"
return self._pagination(url)

View File

@@ -145,4 +145,46 @@ __tests__ = (
"#class" : pornpics.PornpicsSearchExtractor,
},
{
"#url" : "https://www.pornpics.com/ass/",
"#category": ("", "pornpics", "category"),
"#class" : pornpics.PornpicsCategoryExtractor,
"#pattern" : pornpics.PornpicsGalleryExtractor.pattern,
"#range" : "1-50",
"#count" : 50,
},
{
"#url" : "https://www.pornpics.com/milf/",
"#category": ("", "pornpics", "category"),
"#class" : pornpics.PornpicsCategoryExtractor,
},
{
"#url" : "https://pornpics.com/de/blonde",
"#category": ("", "pornpics", "category"),
"#class" : pornpics.PornpicsCategoryExtractor,
},
{
"#url" : "https://www.pornpics.com/popular/",
"#category": ("", "pornpics", "listing"),
"#class" : pornpics.PornpicsListingExtractor,
"#pattern" : pornpics.PornpicsGalleryExtractor.pattern,
"#range" : "1-20",
"#count" : 20,
},
{
"#url" : "https://www.pornpics.com/recent/",
"#category": ("", "pornpics", "listing"),
"#class" : pornpics.PornpicsListingExtractor,
},
{
"#url" : "https://pornpics.com/fr/rating",
"#category": ("", "pornpics", "listing"),
"#class" : pornpics.PornpicsListingExtractor,
},
)